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"
38 #include "wx/stockitem.h"
39 #include "wx/calctrl.h"
40 #include "wx/popupwin.h"
41 #include "wx/renderer.h"
42 #include "wx/dcbuffer.h"
45 //-----------------------------------------------------------------------------
47 //-----------------------------------------------------------------------------
51 static const int SCROLL_UNIT_X
= 15;
53 // the cell padding on the left/right
54 static const int PADDING_RIGHTLEFT
= 3;
56 // the cell padding on the top/bottom
57 static const int PADDING_TOPBOTTOM
= 1;
60 //-----------------------------------------------------------------------------
61 // wxDataViewHeaderWindow
62 //-----------------------------------------------------------------------------
64 #define USE_NATIVE_HEADER_WINDOW 1
66 class wxDataViewHeaderWindowBase
: public wxControl
69 wxDataViewHeaderWindowBase()
72 bool Create(wxDataViewCtrl
*parent
, wxWindowID id
,
73 const wxPoint
&pos
, const wxSize
&size
,
76 return wxWindow::Create(parent
, id
, pos
, size
, wxNO_BORDER
, name
);
79 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
80 wxDataViewCtrl
*GetOwner() { return m_owner
; }
82 // called on column addition/removal
83 virtual void UpdateDisplay() { /* by default, do nothing */ }
85 // returns the n-th column
86 virtual wxDataViewColumn
*GetColumn(unsigned int n
)
89 wxDataViewColumn
*ret
= m_owner
->GetColumn(n
);
96 wxDataViewCtrl
*m_owner
;
98 // sends an event generated from the n-th wxDataViewColumn
99 void SendEvent(wxEventType type
, unsigned int n
);
102 // on wxMSW the header window (only that part however) can be made native!
103 #if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW
105 #define COLUMN_WIDTH_OFFSET 2
106 #define wxDataViewHeaderWindowMSW wxDataViewHeaderWindow
108 class wxDataViewHeaderWindowMSW
: public wxDataViewHeaderWindowBase
112 wxDataViewHeaderWindowMSW( wxDataViewCtrl
*parent
,
114 const wxPoint
&pos
= wxDefaultPosition
,
115 const wxSize
&size
= wxDefaultSize
,
116 const wxString
&name
= wxT("wxdataviewctrlheaderwindow") )
118 Create(parent
, id
, pos
, size
, name
);
121 bool Create(wxDataViewCtrl
*parent
, wxWindowID id
,
122 const wxPoint
&pos
, const wxSize
&size
,
123 const wxString
&name
);
125 ~wxDataViewHeaderWindowMSW();
127 // called when any column setting is changed and/or changed
129 virtual void UpdateDisplay();
131 // called when the main window gets scrolled
132 virtual void ScrollWindow(int dx
, int dy
, const wxRect
*rect
= NULL
);
135 virtual bool MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
);
136 virtual void DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
);
138 unsigned int GetColumnIdxFromHeader(NMHEADER
*nmHDR
);
140 wxDataViewColumn
*GetColumnFromHeader(NMHEADER
*nmHDR
)
141 { return GetColumn(GetColumnIdxFromHeader(nmHDR
)); }
144 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindowMSW
)
147 #else // !defined(__WXMSW__)
149 #define HEADER_WINDOW_HEIGHT 25
150 #define HEADER_HORIZ_BORDER 5
151 #define HEADER_VERT_BORDER 3
152 #define wxGenericDataViewHeaderWindow wxDataViewHeaderWindow
154 class wxGenericDataViewHeaderWindow
: public wxDataViewHeaderWindowBase
157 wxGenericDataViewHeaderWindow( wxDataViewCtrl
*parent
,
159 const wxPoint
&pos
= wxDefaultPosition
,
160 const wxSize
&size
= wxDefaultSize
,
161 const wxString
&name
= wxT("wxdataviewctrlheaderwindow") )
164 Create(parent
, id
, pos
, size
, name
);
167 bool Create(wxDataViewCtrl
*parent
, wxWindowID id
,
168 const wxPoint
&pos
, const wxSize
&size
,
169 const wxString
&name
);
171 ~wxGenericDataViewHeaderWindow()
173 delete m_resizeCursor
;
178 void OnPaint( wxPaintEvent
&event
);
179 void OnMouse( wxMouseEvent
&event
);
180 void OnSetFocus( wxFocusEvent
&event
);
185 // vars used for column resizing:
187 wxCursor
*m_resizeCursor
;
188 const wxCursor
*m_currentCursor
;
191 bool m_dirty
; // needs refresh?
192 int m_column
; // index of the column being resized
193 int m_currentX
; // divider line position in logical (unscrolled) coords
194 int m_minX
; // minimal position beyond which the divider line
195 // can't be dragged in logical coords
197 // the pen used to draw the current column width drag line
198 // when resizing the columsn
202 // internal utilities:
206 m_currentCursor
= (wxCursor
*) NULL
;
207 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
209 m_isDragging
= false;
212 m_column
= wxNOT_FOUND
;
216 wxColour col
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
);
217 m_penCurrent
= wxPen(col
, 1, wxSOLID
);
221 void AdjustDC(wxDC
& dc
);
224 DECLARE_DYNAMIC_CLASS(wxGenericDataViewHeaderWindow
)
225 DECLARE_EVENT_TABLE()
228 #endif // defined(__WXMSW__)
230 //-----------------------------------------------------------------------------
231 // wxDataViewRenameTimer
232 //-----------------------------------------------------------------------------
234 class wxDataViewRenameTimer
: public wxTimer
237 wxDataViewMainWindow
*m_owner
;
240 wxDataViewRenameTimer( wxDataViewMainWindow
*owner
);
244 //-----------------------------------------------------------------------------
245 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
246 //-----------------------------------------------------------------------------
248 class wxDataViewTextCtrlWrapper
: public wxEvtHandler
251 // NB: text must be a valid object but not Create()d yet
252 wxDataViewTextCtrlWrapper( wxDataViewMainWindow
*owner
,
254 wxDataViewListModel
*model
,
255 unsigned int col
, unsigned int row
,
258 wxTextCtrl
*GetText() const { return m_text
; }
260 void AcceptChangesAndFinish();
263 void OnChar( wxKeyEvent
&event
);
264 void OnKeyUp( wxKeyEvent
&event
);
265 void OnKillFocus( wxFocusEvent
&event
);
267 bool AcceptChanges();
271 wxDataViewMainWindow
*m_owner
;
273 wxString m_startValue
;
274 wxDataViewListModel
*m_model
;
278 bool m_aboutToFinish
;
280 DECLARE_EVENT_TABLE()
283 //-----------------------------------------------------------------------------
284 // wxDataViewMainWindow
285 //-----------------------------------------------------------------------------
287 WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection
,
290 class wxDataViewMainWindow
: public wxWindow
293 wxDataViewMainWindow( wxDataViewCtrl
*parent
,
295 const wxPoint
&pos
= wxDefaultPosition
,
296 const wxSize
&size
= wxDefaultSize
,
297 const wxString
&name
= wxT("wxdataviewctrlmainwindow") );
298 virtual ~wxDataViewMainWindow();
300 // notifications from wxDataViewListModel
303 bool RowInserted( unsigned int before
);
304 bool RowDeleted( unsigned int row
);
305 bool RowChanged( unsigned int row
);
306 bool ValueChanged( unsigned int col
, unsigned int row
);
307 bool RowsReordered( unsigned int *new_order
);
310 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
311 wxDataViewCtrl
*GetOwner() { return m_owner
; }
312 const wxDataViewCtrl
*GetOwner() const { return m_owner
; }
314 void OnPaint( wxPaintEvent
&event
);
315 void OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
);
316 void OnChar( wxKeyEvent
&event
);
317 void OnMouse( wxMouseEvent
&event
);
318 void OnSetFocus( wxFocusEvent
&event
);
319 void OnKillFocus( wxFocusEvent
&event
);
321 void UpdateDisplay();
322 void RecalculateDisplay();
323 void OnInternalIdle();
325 void OnRenameTimer();
326 void FinishEditing( wxTextCtrl
*text
);
328 void ScrollWindow( int dx
, int dy
, const wxRect
*rect
= NULL
);
330 bool HasCurrentRow() { return m_currentRow
!= (unsigned int)-1; }
331 void ChangeCurrentRow( unsigned int row
);
333 bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE
); };
334 bool IsEmpty() { return GetRowCount() == 0; }
336 int GetCountPerPage() const;
337 int GetEndOfLastCol() const;
338 unsigned int GetFirstVisibleRow() const;
339 unsigned int GetLastVisibleRow() const;
340 unsigned int GetRowCount() const;
342 void Select( const wxArrayInt
& aSelections
);
343 void SelectAllRows( bool on
);
344 void SelectRow( unsigned int row
, bool on
);
345 void SelectRows( unsigned int from
, unsigned int to
, bool on
);
346 void ReverseRowSelection( unsigned int row
);
347 bool IsRowSelected( unsigned int row
);
349 void RefreshRow( unsigned int row
);
350 void RefreshRows( unsigned int from
, unsigned int to
);
351 void RefreshRowsAfter( unsigned int firstRow
);
353 // returns the colour to be used for drawing the rules
354 wxColour
GetRuleColour() const
356 return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
);
359 //void EnsureVisible( unsigned int row );
360 wxRect
GetLineRect( unsigned int row
) const;
363 wxDataViewCtrl
*m_owner
;
367 wxDataViewColumn
*m_currentCol
;
368 unsigned int m_currentRow
;
369 wxDataViewSelection m_selection
;
371 wxDataViewRenameTimer
*m_renameTimer
;
372 wxDataViewTextCtrlWrapper
*m_textctrlWrapper
;
380 // for double click logic
381 unsigned int m_lineLastClicked
,
382 m_lineBeforeLastClicked
,
383 m_lineSelectSingleOnUp
;
385 // the pen used to draw horiz/vertical rules
389 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
)
390 DECLARE_EVENT_TABLE()
393 // ---------------------------------------------------------
394 // wxGenericDataViewListModelNotifier
395 // ---------------------------------------------------------
397 class wxGenericDataViewListModelNotifier
: public wxDataViewListModelNotifier
400 wxGenericDataViewListModelNotifier( wxDataViewMainWindow
*mainWindow
)
401 { m_mainWindow
= mainWindow
; }
403 virtual bool RowAppended()
404 { return m_mainWindow
->RowAppended(); }
405 virtual bool RowPrepended()
406 { return m_mainWindow
->RowPrepended(); }
407 virtual bool RowInserted( unsigned int before
)
408 { return m_mainWindow
->RowInserted( before
); }
409 virtual bool RowDeleted( unsigned int row
)
410 { return m_mainWindow
->RowDeleted( row
); }
411 virtual bool RowChanged( unsigned int row
)
412 { return m_mainWindow
->RowChanged( row
); }
413 virtual bool ValueChanged( unsigned int col
, unsigned int row
)
414 { return m_mainWindow
->ValueChanged( col
, row
); }
415 virtual bool RowsReordered( unsigned int *new_order
)
416 { return m_mainWindow
->RowsReordered( new_order
); }
417 virtual bool Cleared()
418 { return m_mainWindow
->Cleared(); }
420 wxDataViewMainWindow
*m_mainWindow
;
423 // ---------------------------------------------------------
424 // wxDataViewRenderer
425 // ---------------------------------------------------------
427 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer
, wxDataViewRendererBase
)
429 wxDataViewRenderer::wxDataViewRenderer( const wxString
&varianttype
,
430 wxDataViewCellMode mode
,
432 wxDataViewRendererBase( varianttype
, mode
, align
)
439 wxDataViewRenderer::~wxDataViewRenderer()
445 wxDC
*wxDataViewRenderer::GetDC()
449 if (GetOwner() == NULL
)
451 if (GetOwner()->GetOwner() == NULL
)
453 m_dc
= new wxClientDC( GetOwner()->GetOwner() );
460 // ---------------------------------------------------------
461 // wxDataViewCustomRenderer
462 // ---------------------------------------------------------
464 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer
, wxDataViewRenderer
)
466 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString
&varianttype
,
467 wxDataViewCellMode mode
, int align
) :
468 wxDataViewRenderer( varianttype
, mode
, align
)
472 // ---------------------------------------------------------
473 // wxDataViewTextRenderer
474 // ---------------------------------------------------------
476 IMPLEMENT_CLASS(wxDataViewTextRenderer
, wxDataViewCustomRenderer
)
478 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString
&varianttype
,
479 wxDataViewCellMode mode
, int align
) :
480 wxDataViewCustomRenderer( varianttype
, mode
, align
)
484 bool wxDataViewTextRenderer::SetValue( const wxVariant
&value
)
486 m_text
= value
.GetString();
491 bool wxDataViewTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const
496 bool wxDataViewTextRenderer::Render( wxRect cell
, wxDC
*dc
, int state
)
498 wxDataViewCtrl
*view
= GetOwner()->GetOwner();
499 wxColour col
= (state
& wxDATAVIEW_CELL_SELECTED
) ?
500 wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
) :
501 view
->GetForegroundColour();
503 dc
->SetTextForeground(col
);
504 dc
->DrawText( m_text
, cell
.x
, cell
.y
);
509 wxSize
wxDataViewTextRenderer::GetSize() const
511 const wxDataViewCtrl
*view
= GetView();
515 view
->GetTextExtent( m_text
, &x
, &y
);
516 return wxSize( x
, y
);
518 return wxSize(80,20);
521 // ---------------------------------------------------------
522 // wxDataViewBitmapRenderer
523 // ---------------------------------------------------------
525 IMPLEMENT_CLASS(wxDataViewBitmapRenderer
, wxDataViewCustomRenderer
)
527 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString
&varianttype
,
528 wxDataViewCellMode mode
, int align
) :
529 wxDataViewCustomRenderer( varianttype
, mode
, align
)
533 bool wxDataViewBitmapRenderer::SetValue( const wxVariant
&value
)
535 if (value
.GetType() == wxT("wxBitmap"))
537 if (value
.GetType() == wxT("wxIcon"))
543 bool wxDataViewBitmapRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const
548 bool wxDataViewBitmapRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
551 dc
->DrawBitmap( m_bitmap
, cell
.x
, cell
.y
);
552 else if (m_icon
.Ok())
553 dc
->DrawIcon( m_icon
, cell
.x
, cell
.y
);
558 wxSize
wxDataViewBitmapRenderer::GetSize() const
561 return wxSize( m_bitmap
.GetWidth(), m_bitmap
.GetHeight() );
562 else if (m_icon
.Ok())
563 return wxSize( m_icon
.GetWidth(), m_icon
.GetHeight() );
565 return wxSize(16,16);
568 // ---------------------------------------------------------
569 // wxDataViewToggleRenderer
570 // ---------------------------------------------------------
572 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer
, wxDataViewCustomRenderer
)
574 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString
&varianttype
,
575 wxDataViewCellMode mode
, int align
) :
576 wxDataViewCustomRenderer( varianttype
, mode
, align
)
581 bool wxDataViewToggleRenderer::SetValue( const wxVariant
&value
)
583 m_toggle
= value
.GetBool();
588 bool wxDataViewToggleRenderer::GetValue( wxVariant
&WXUNUSED(value
) ) const
593 bool wxDataViewToggleRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
595 // User wxRenderer here
598 rect
.x
= cell
.x
+ cell
.width
/2 - 10;
600 rect
.y
= cell
.y
+ cell
.height
/2 - 10;
605 flags
|= wxCONTROL_CHECKED
;
606 if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE
)
607 flags
|= wxCONTROL_DISABLED
;
609 wxRendererNative::Get().DrawCheckBox(
610 GetOwner()->GetOwner(),
618 bool wxDataViewToggleRenderer::Activate( wxRect
WXUNUSED(cell
),
619 wxDataViewListModel
*model
,
620 unsigned int col
, unsigned int row
)
622 bool value
= !m_toggle
;
623 wxVariant variant
= value
;
624 model
->SetValue( variant
, col
, row
);
625 model
->ValueChanged( col
, row
);
629 wxSize
wxDataViewToggleRenderer::GetSize() const
631 return wxSize(20,20);
634 // ---------------------------------------------------------
635 // wxDataViewProgressRenderer
636 // ---------------------------------------------------------
638 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer
, wxDataViewCustomRenderer
)
640 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString
&label
,
641 const wxString
&varianttype
, wxDataViewCellMode mode
, int align
) :
642 wxDataViewCustomRenderer( varianttype
, mode
, align
)
648 wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
652 bool wxDataViewProgressRenderer::SetValue( const wxVariant
&value
)
654 m_value
= (long) value
;
656 if (m_value
< 0) m_value
= 0;
657 if (m_value
> 100) m_value
= 100;
662 bool wxDataViewProgressRenderer::GetValue( wxVariant
&value
) const
664 value
= (long) m_value
;
668 bool wxDataViewProgressRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
670 double pct
= (double)m_value
/ 100.0;
672 bar
.width
= (int)(cell
.width
* pct
);
673 dc
->SetPen( *wxTRANSPARENT_PEN
);
674 dc
->SetBrush( *wxBLUE_BRUSH
);
675 dc
->DrawRectangle( bar
);
677 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
678 dc
->SetPen( *wxBLACK_PEN
);
679 dc
->DrawRectangle( cell
);
684 wxSize
wxDataViewProgressRenderer::GetSize() const
686 return wxSize(40,12);
689 // ---------------------------------------------------------
690 // wxDataViewDateRenderer
691 // ---------------------------------------------------------
693 #define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN)
695 #if wxUSE_DATE_RENDERER_POPUP
697 class wxDataViewDateRendererPopupTransient
: public wxPopupTransientWindow
700 wxDataViewDateRendererPopupTransient( wxWindow
* parent
, wxDateTime
*value
,
701 wxDataViewListModel
*model
, unsigned int col
, unsigned int row
) :
702 wxPopupTransientWindow( parent
, wxBORDER_SIMPLE
)
707 m_cal
= new wxCalendarCtrl( this, wxID_ANY
, *value
);
708 wxBoxSizer
*sizer
= new wxBoxSizer( wxHORIZONTAL
);
709 sizer
->Add( m_cal
, 1, wxGROW
);
714 void OnCalendar( wxCalendarEvent
&event
);
716 wxCalendarCtrl
*m_cal
;
717 wxDataViewListModel
*m_model
;
722 virtual void OnDismiss()
727 DECLARE_EVENT_TABLE()
730 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient
,wxPopupTransientWindow
)
731 EVT_CALENDAR( wxID_ANY
, wxDataViewDateRendererPopupTransient::OnCalendar
)
734 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent
&event
)
736 wxDateTime date
= event
.GetDate();
737 wxVariant value
= date
;
738 m_model
->SetValue( value
, m_col
, m_row
);
739 m_model
->ValueChanged( m_col
, m_row
);
743 #endif // wxUSE_DATE_RENDERER_POPUP
745 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer
, wxDataViewCustomRenderer
)
747 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString
&varianttype
,
748 wxDataViewCellMode mode
, int align
) :
749 wxDataViewCustomRenderer( varianttype
, mode
, align
)
753 bool wxDataViewDateRenderer::SetValue( const wxVariant
&value
)
755 m_date
= value
.GetDateTime();
760 bool wxDataViewDateRenderer::GetValue( wxVariant
&value
) const
766 bool wxDataViewDateRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
768 dc
->SetFont( GetOwner()->GetOwner()->GetFont() );
769 wxString tmp
= m_date
.FormatDate();
770 dc
->DrawText( tmp
, cell
.x
, cell
.y
);
775 wxSize
wxDataViewDateRenderer::GetSize() const
777 const wxDataViewCtrl
* view
= GetView();
778 wxString tmp
= m_date
.FormatDate();
780 view
->GetTextExtent( tmp
, &x
, &y
, &d
);
781 return wxSize(x
,y
+d
);
784 bool wxDataViewDateRenderer::Activate( wxRect
WXUNUSED(cell
), wxDataViewListModel
*model
,
785 unsigned int col
, unsigned int row
)
788 model
->GetValue( variant
, col
, row
);
789 wxDateTime value
= variant
.GetDateTime();
791 #if wxUSE_DATE_RENDERER_POPUP
792 wxDataViewDateRendererPopupTransient
*popup
= new wxDataViewDateRendererPopupTransient(
793 GetOwner()->GetOwner()->GetParent(), &value
, model
, col
, row
);
794 wxPoint pos
= wxGetMousePosition();
797 popup
->Popup( popup
->m_cal
);
798 #else // !wxUSE_DATE_RENDERER_POPUP
799 wxMessageBox(value
.Format());
800 #endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP
804 // ---------------------------------------------------------
806 // ---------------------------------------------------------
808 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn
, wxDataViewColumnBase
)
810 wxDataViewColumn::wxDataViewColumn( const wxString
&title
, wxDataViewRenderer
*cell
,
811 unsigned int model_column
,
812 int width
, wxAlignment align
, int flags
) :
813 wxDataViewColumnBase( title
, cell
, model_column
, width
, align
, flags
)
819 Init(width
< 0 ? wxDVC_DEFAULT_WIDTH
: width
);
822 wxDataViewColumn::wxDataViewColumn( const wxBitmap
&bitmap
, wxDataViewRenderer
*cell
,
823 unsigned int model_column
,
824 int width
, wxAlignment align
, int flags
) :
825 wxDataViewColumnBase( bitmap
, cell
, model_column
, width
, align
, flags
)
830 Init(width
< 0 ? wxDVC_TOGGLE_DEFAULT_WIDTH
: width
);
833 wxDataViewColumn::~wxDataViewColumn()
837 void wxDataViewColumn::Init( int width
)
840 m_minWidth
= wxDVC_DEFAULT_MINWIDTH
;
843 void wxDataViewColumn::SetResizeable( bool resizeable
)
846 m_flags
|= wxDATAVIEW_COL_RESIZABLE
;
848 m_flags
&= ~wxDATAVIEW_COL_RESIZABLE
;
851 void wxDataViewColumn::SetHidden( bool hidden
)
854 m_flags
|= wxDATAVIEW_COL_HIDDEN
;
856 m_flags
&= ~wxDATAVIEW_COL_HIDDEN
;
858 // tell our owner to e.g. update its scrollbars:
860 GetOwner()->OnColumnChange();
863 void wxDataViewColumn::SetSortable( bool sortable
)
866 m_flags
|= wxDATAVIEW_COL_SORTABLE
;
868 m_flags
&= ~wxDATAVIEW_COL_SORTABLE
;
871 void wxDataViewColumn::SetSortOrder( bool WXUNUSED(ascending
) )
876 bool wxDataViewColumn::IsSortOrderAscending() const
882 void wxDataViewColumn::SetInternalWidth( int width
)
886 // the scrollbars of the wxDataViewCtrl needs to be recalculated!
887 if (m_owner
&& m_owner
->m_clientArea
)
888 m_owner
->m_clientArea
->RecalculateDisplay();
891 void wxDataViewColumn::SetWidth( int width
)
893 m_owner
->m_headerArea
->UpdateDisplay();
895 SetInternalWidth(width
);
899 //-----------------------------------------------------------------------------
900 // wxDataViewHeaderWindowBase
901 //-----------------------------------------------------------------------------
903 void wxDataViewHeaderWindowBase::SendEvent(wxEventType type
, unsigned int n
)
905 wxWindow
*parent
= GetParent();
906 wxDataViewEvent
le(type
, parent
->GetId());
908 le
.SetEventObject(parent
);
910 le
.SetDataViewColumn(GetColumn(n
));
911 le
.SetModel(GetOwner()->GetModel());
913 // for events created by wxDataViewHeaderWindow the
914 // row / value fields are not valid
916 parent
->GetEventHandler()->ProcessEvent(le
);
919 #if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW
921 // implemented in msw/window.cpp:
922 void wxAssociateWinWithHandle(HWND hWnd
, wxWindowMSW
*win
);
923 void wxRemoveHandleAssociation(wxWindowMSW
*win
);
925 // implemented in msw/listctrl.cpp:
926 unsigned int wxMSWGetColumnClicked(NMHDR
*nmhdr
, POINT
*ptClick
);
928 IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindowMSW
, wxWindow
);
930 bool wxDataViewHeaderWindowMSW::Create( wxDataViewCtrl
*parent
, wxWindowID id
,
931 const wxPoint
&pos
, const wxSize
&size
,
932 const wxString
&name
)
936 if ( !CreateControl(parent
, id
, pos
, size
, 0, wxDefaultValidator
, name
) )
939 int x
= pos
.x
== wxDefaultCoord
? 0 : pos
.x
,
940 y
= pos
.y
== wxDefaultCoord
? 0 : pos
.y
,
941 w
= size
.x
== wxDefaultCoord
? 1 : size
.x
,
942 h
= size
.y
== wxDefaultCoord
? 22 : size
.y
;
944 // create the native WC_HEADER window:
945 WXHWND hwndParent
= (HWND
)parent
->GetHandle();
946 WXDWORD msStyle
= WS_CHILD
| HDS_BUTTONS
| HDS_HORZ
| HDS_HOTTRACK
| HDS_FULLDRAG
;
947 m_hWnd
= CreateWindowEx(0,
958 wxLogLastError(_T("CreateWindowEx"));
962 // we need to do the association to force wxWindow::HandleNotify
963 // to call wxDataViewHeaderWindow::MSWOnNotify
964 wxAssociateWinWithHandle((HWND
)m_hWnd
, this);
966 // the following is required to get the default win's font for
967 // header windows and must be done befor sending the HDM_LAYOUT msg
974 // Retrieve the bounding rectangle of the parent window's
975 // client area, and then request size and position values
976 // from the header control.
977 ::GetClientRect((HWND
)hwndParent
, &rcParent
);
981 if (!SendMessage((HWND
)m_hWnd
, HDM_LAYOUT
, 0, (LPARAM
) &hdl
))
983 wxLogLastError(_T("SendMessage"));
987 // Set the size, position, and visibility of the header control.
988 SetWindowPos((HWND
)m_hWnd
,
992 wp
.flags
| SWP_SHOWWINDOW
);
994 // set our size hints: wxDataViewCtrl will put this wxWindow inside
995 // a wxBoxSizer and in order to avoid super-big header windows,
996 // we need to set our height as fixed
997 SetMinSize(wxSize(-1, wp
.cy
));
998 SetMaxSize(wxSize(-1, wp
.cy
));
1003 wxDataViewHeaderWindowMSW::~wxDataViewHeaderWindow()
1005 wxRemoveHandleAssociation(this);
1008 void wxDataViewHeaderWindowMSW::UpdateDisplay()
1010 // remove old columns
1011 for (int i
=0, max
=Header_GetItemCount((HWND
)m_hWnd
); i
< max
; i
++)
1012 Header_DeleteItem((HWND
)m_hWnd
, 0);
1014 // add the updated array of columns to the header control
1015 unsigned int cols
= GetOwner()->GetColumnCount();
1016 unsigned int added
= 0;
1017 for (unsigned int i
= 0; i
< cols
; i
++)
1019 wxDataViewColumn
*col
= GetColumn( i
);
1020 if (col
->IsHidden())
1021 continue; // don't add it!
1024 hdi
.mask
= HDI_TEXT
| HDI_FORMAT
| HDI_WIDTH
;
1025 hdi
.pszText
= (wxChar
*) col
->GetTitle().c_str();
1026 hdi
.cxy
= col
->GetWidth();
1027 hdi
.cchTextMax
= sizeof(hdi
.pszText
)/sizeof(hdi
.pszText
[0]);
1028 hdi
.fmt
= HDF_LEFT
| HDF_STRING
;
1030 // lParam is reserved for application's use:
1031 // we store there the column index to use it later in MSWOnNotify
1032 // (since columns may have been hidden)
1033 hdi
.lParam
= (LPARAM
)i
;
1035 // the native wxMSW implementation of the header window
1036 // draws the column separator COLUMN_WIDTH_OFFSET pixels
1037 // on the right: to correct this effect we make the column
1038 // exactly COLUMN_WIDTH_OFFSET wider (for the first column):
1040 hdi
.cxy
+= COLUMN_WIDTH_OFFSET
;
1042 switch (col
->GetAlignment())
1045 hdi
.fmt
|= HDF_LEFT
;
1047 case wxALIGN_CENTER
:
1048 case wxALIGN_CENTER_HORIZONTAL
:
1049 hdi
.fmt
|= HDF_CENTER
;
1052 hdi
.fmt
|= HDF_RIGHT
;
1056 SendMessage((HWND
)m_hWnd
, HDM_INSERTITEM
,
1057 (WPARAM
)added
, (LPARAM
)&hdi
);
1062 unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER
*nmHDR
)
1066 // NOTE: we don't just return nmHDR->iItem because when there are
1067 // hidden columns, nmHDR->iItem may be different from
1068 // nmHDR->pitem->lParam
1070 if (nmHDR
->pitem
&& nmHDR
->pitem
->mask
& HDI_LPARAM
)
1072 idx
= (unsigned int)nmHDR
->pitem
->lParam
;
1077 item
.mask
= HDI_LPARAM
;
1078 Header_GetItem((HWND
)m_hWnd
, nmHDR
->iItem
, &item
);
1080 return (unsigned int)item
.lParam
;
1083 bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
1085 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
1087 // is it a message from the header?
1088 if ( nmhdr
->hwndFrom
!= (HWND
)m_hWnd
)
1089 return wxWindow::MSWOnNotify(idCtrl
, lParam
, result
);
1091 NMHEADER
*nmHDR
= (NMHEADER
*)nmhdr
;
1092 switch ( nmhdr
->code
)
1094 case HDN_BEGINTRACK
:
1095 // user has started to resize a column:
1096 // do we need to veto it?
1097 if (!GetColumn(nmHDR
->iItem
)->IsResizeable())
1105 // user has started to reorder a column
1108 case HDN_ITEMCHANGING
:
1109 if (nmHDR
->pitem
!= NULL
&&
1110 (nmHDR
->pitem
->mask
& HDI_WIDTH
) != 0)
1112 int minWidth
= GetColumnFromHeader(nmHDR
)->GetMinWidth();
1113 if (nmHDR
->pitem
->cxy
< minWidth
)
1115 // do not allow the user to resize this column under
1116 // its minimal width:
1122 case HDN_ITEMCHANGED
: // user is resizing a column
1123 case HDN_ENDTRACK
: // user has finished resizing a column
1124 case HDN_ENDDRAG
: // user has finished reordering a column
1126 // update the width of the modified column:
1127 if (nmHDR
->pitem
!= NULL
&&
1128 (nmHDR
->pitem
->mask
& HDI_WIDTH
) != 0)
1130 unsigned int idx
= GetColumnIdxFromHeader(nmHDR
);
1131 unsigned int w
= nmHDR
->pitem
->cxy
;
1132 wxDataViewColumn
*col
= GetColumn(idx
);
1134 // see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET
1135 if (idx
== 0 && w
> COLUMN_WIDTH_OFFSET
)
1136 w
-= COLUMN_WIDTH_OFFSET
;
1138 if (w
>= (unsigned)col
->GetMinWidth())
1139 col
->SetInternalWidth(w
);
1145 unsigned int idx
= GetColumnIdxFromHeader(nmHDR
);
1146 wxEventType evt
= nmHDR
->iButton
== 0 ?
1147 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
:
1148 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
;
1149 SendEvent(evt
, idx
);
1155 // NOTE: for some reason (i.e. for a bug in Windows)
1156 // the HDN_ITEMCLICK notification is not sent on
1157 // right clicks, so we need to handle NM_RCLICK
1160 int column
= wxMSWGetColumnClicked(nmhdr
, &ptClick
);
1161 if (column
!= wxNOT_FOUND
)
1164 item
.mask
= HDI_LPARAM
;
1165 Header_GetItem((HWND
)m_hWnd
, column
, &item
);
1167 // 'idx' may be different from 'column' if there are
1168 // hidden columns...
1169 unsigned int idx
= (unsigned int)item
.lParam
;
1170 SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
,
1176 case HDN_GETDISPINFOW
:
1177 // see wxListCtrl::MSWOnNotify for more info!
1180 case HDN_ITEMDBLCLICK
:
1182 unsigned int idx
= GetColumnIdxFromHeader(nmHDR
);
1183 int w
= GetOwner()->GetBestColumnWidth(idx
);
1185 // update the native control:
1187 ZeroMemory(&hd
, sizeof(hd
));
1188 hd
.mask
= HDI_WIDTH
;
1190 Header_SetItem(GetHwnd(),
1191 nmHDR
->iItem
, // NOTE: we don't want 'idx' here!
1194 // update the wxDataViewColumn class:
1195 GetColumn(idx
)->SetInternalWidth(w
);
1200 return wxWindow::MSWOnNotify(idCtrl
, lParam
, result
);
1206 void wxDataViewHeaderWindowMSW::ScrollWindow(int WXUNUSED(dx
), int WXUNUSED(dy
),
1207 const wxRect
*WXUNUSED(rect
))
1209 wxSize ourSz
= GetClientSize();
1210 wxSize ownerSz
= m_owner
->GetClientSize();
1212 // where should the (logical) origin of this window be placed?
1214 m_owner
->CalcUnscrolledPosition(0, 0, &x1
, &y1
);
1216 // put this window on top of our parent and
1217 SetWindowPos((HWND
)m_hWnd
, HWND_TOP
, -x1
, 0,
1218 ownerSz
.GetWidth() + x1
, ourSz
.GetHeight(),
1222 void wxDataViewHeaderWindowMSW::DoSetSize(int WXUNUSED(x
), int WXUNUSED(y
),
1223 int WXUNUSED(w
), int WXUNUSED(h
),
1226 // the wxDataViewCtrl's internal wxBoxSizer will call this function when
1227 // the wxDataViewCtrl window gets resized: the following dummy call
1228 // to ScrollWindow() is required in order to get this header window
1229 // correctly repainted when it's (horizontally) scrolled:
1234 #else // !defined(__WXMSW__)
1236 IMPLEMENT_ABSTRACT_CLASS(wxGenericDataViewHeaderWindow
, wxWindow
)
1237 BEGIN_EVENT_TABLE(wxGenericDataViewHeaderWindow
, wxWindow
)
1238 EVT_PAINT (wxGenericDataViewHeaderWindow::OnPaint
)
1239 EVT_MOUSE_EVENTS (wxGenericDataViewHeaderWindow::OnMouse
)
1240 EVT_SET_FOCUS (wxGenericDataViewHeaderWindow::OnSetFocus
)
1243 bool wxGenericDataViewHeaderWindow::Create(wxDataViewCtrl
*parent
, wxWindowID id
,
1244 const wxPoint
&pos
, const wxSize
&size
,
1245 const wxString
&name
)
1249 if (!wxDataViewHeaderWindowBase::Create(parent
, id
, pos
, size
, name
))
1252 wxVisualAttributes attr
= wxPanel::GetClassDefaultAttributes();
1253 SetBackgroundStyle( wxBG_STYLE_CUSTOM
);
1254 SetOwnForegroundColour( attr
.colFg
);
1255 SetOwnBackgroundColour( attr
.colBg
);
1257 SetOwnFont( attr
.font
);
1259 // set our size hints: wxDataViewCtrl will put this wxWindow inside
1260 // a wxBoxSizer and in order to avoid super-big header windows,
1261 // we need to set our height as fixed
1262 SetMinSize(wxSize(-1, HEADER_WINDOW_HEIGHT
));
1263 SetMaxSize(wxSize(-1, HEADER_WINDOW_HEIGHT
));
1268 void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1271 GetClientSize( &w
, &h
);
1273 wxAutoBufferedPaintDC
dc( this );
1275 dc
.SetBackground(GetBackgroundColour());
1279 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1282 m_owner
->GetViewStart( &x
, NULL
);
1284 // account for the horz scrollbar offset
1285 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1287 dc
.SetFont( GetFont() );
1289 unsigned int cols
= GetOwner()->GetColumnCount();
1292 for (i
= 0; i
< cols
; i
++)
1294 wxDataViewColumn
*col
= GetColumn( i
);
1295 if (col
->IsHidden())
1296 continue; // skip it!
1298 int cw
= col
->GetWidth();
1301 wxRendererNative::Get().DrawHeaderButton
1305 wxRect(xpos
, 0, cw
, ch
-1),
1306 m_parent
->IsEnabled() ? 0
1307 : (int)wxCONTROL_DISABLED
1310 // align as required the column title:
1312 wxSize titleSz
= dc
.GetTextExtent(col
->GetTitle());
1313 switch (col
->GetAlignment())
1316 x
+= HEADER_HORIZ_BORDER
;
1318 case wxALIGN_CENTER
:
1319 case wxALIGN_CENTER_HORIZONTAL
:
1320 x
+= (cw
- titleSz
.GetWidth() - 2 * HEADER_HORIZ_BORDER
)/2;
1323 x
+= cw
- titleSz
.GetWidth() - HEADER_HORIZ_BORDER
;
1327 // always center the title vertically:
1328 int y
= wxMax((ch
- titleSz
.GetHeight()) / 2, HEADER_VERT_BORDER
);
1330 dc
.SetClippingRegion( xpos
+HEADER_HORIZ_BORDER
,
1332 wxMax(cw
- 2 * HEADER_HORIZ_BORDER
, 1), // width
1333 wxMax(ch
- 2 * HEADER_VERT_BORDER
, 1)); // height
1334 dc
.DrawText( col
->GetTitle(), x
, y
);
1335 dc
.DestroyClippingRegion();
1341 void wxGenericDataViewHeaderWindow::OnSetFocus( wxFocusEvent
&event
)
1343 GetParent()->SetFocus();
1347 void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent
&event
)
1349 // we want to work with logical coords
1351 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1352 int y
= event
.GetY();
1356 // we don't draw the line beyond our window,
1357 // but we allow dragging it there
1359 GetClientSize( &w
, NULL
);
1360 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1363 // erase the line if it was drawn
1367 if (event
.ButtonUp())
1369 m_isDragging
= false;
1375 GetColumn(m_column
)->SetWidth(m_currentX
- m_minX
);
1378 GetOwner()->Refresh();
1382 m_currentX
= wxMax(m_minX
+ 7, x
);
1384 // draw in the new location
1385 if (m_currentX
< w
) DrawCurrent();
1389 else // not dragging
1392 m_column
= wxNOT_FOUND
;
1394 bool hit_border
= false;
1396 // end of the current column
1399 // find the column where this event occured
1400 int countCol
= m_owner
->GetColumnCount();
1401 for (int column
= 0; column
< countCol
; column
++)
1403 wxDataViewColumn
*p
= GetColumn(column
);
1406 continue; // skip if not shown
1408 xpos
+= p
->GetWidth();
1410 if ((abs(x
-xpos
) < 3) && (y
< 22))
1418 // inside the column
1425 if (m_column
== wxNOT_FOUND
)
1428 bool resizeable
= GetColumn(m_column
)->IsResizeable();
1429 if (event
.LeftDClick() && resizeable
)
1431 GetColumn(m_column
)->SetWidth(GetOwner()->GetBestColumnWidth(m_column
));
1434 else if (event
.LeftDown() || event
.RightUp())
1436 if (hit_border
&& event
.LeftDown() && resizeable
)
1438 m_isDragging
= true;
1443 else // click on a column
1445 wxEventType evt
= event
.LeftDown() ?
1446 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
:
1447 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
;
1448 SendEvent(evt
, m_column
);
1451 else if (event
.Moving())
1453 if (hit_border
&& resizeable
)
1454 m_currentCursor
= m_resizeCursor
;
1456 m_currentCursor
= wxSTANDARD_CURSOR
;
1458 SetCursor(*m_currentCursor
);
1463 void wxGenericDataViewHeaderWindow::DrawCurrent()
1465 int x1
= m_currentX
;
1467 ClientToScreen (&x1
, &y1
);
1469 int x2
= m_currentX
-1;
1471 ++x2
; // but why ????
1474 m_owner
->GetClientSize( NULL
, &y2
);
1475 m_owner
->ClientToScreen( &x2
, &y2
);
1478 dc
.SetLogicalFunction(wxINVERT
);
1479 dc
.SetPen(m_penCurrent
);
1480 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1482 dc
.DrawLine(x1
, y1
, x2
, y2
);
1485 void wxGenericDataViewHeaderWindow::AdjustDC(wxDC
& dc
)
1489 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1490 m_owner
->GetViewStart( &x
, NULL
);
1492 // shift the DC origin to match the position of the main window horizontal
1493 // scrollbar: this allows us to always use logical coords
1494 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1497 #endif // defined(__WXMSW__)
1499 //-----------------------------------------------------------------------------
1500 // wxDataViewRenameTimer
1501 //-----------------------------------------------------------------------------
1503 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow
*owner
)
1508 void wxDataViewRenameTimer::Notify()
1510 m_owner
->OnRenameTimer();
1513 //-----------------------------------------------------------------------------
1514 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
1515 //-----------------------------------------------------------------------------
1517 BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper
, wxEvtHandler
)
1518 EVT_CHAR (wxDataViewTextCtrlWrapper::OnChar
)
1519 EVT_KEY_UP (wxDataViewTextCtrlWrapper::OnKeyUp
)
1520 EVT_KILL_FOCUS (wxDataViewTextCtrlWrapper::OnKillFocus
)
1523 wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper(
1524 wxDataViewMainWindow
*owner
,
1526 wxDataViewListModel
*model
,
1527 unsigned int col
, unsigned int row
,
1537 m_aboutToFinish
= false;
1540 model
->GetValue( value
, col
, row
);
1541 m_startValue
= value
.GetString();
1543 m_owner
->GetOwner()->CalcScrolledPosition(
1544 rectLabel
.x
, rectLabel
.y
, &rectLabel
.x
, &rectLabel
.y
);
1546 m_text
->Create( owner
, wxID_ANY
, m_startValue
,
1547 wxPoint(rectLabel
.x
-2,rectLabel
.y
-2),
1548 wxSize(rectLabel
.width
+7,rectLabel
.height
+4) );
1551 m_text
->PushEventHandler(this);
1554 void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish()
1556 m_aboutToFinish
= true;
1558 // Notify the owner about the changes
1561 // Even if vetoed, close the control (consistent with MSW)
1565 void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent
&event
)
1567 switch ( event
.m_keyCode
)
1570 AcceptChangesAndFinish();
1574 // m_owner->OnRenameCancelled( m_itemEdited );
1583 void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent
&event
)
1591 // auto-grow the textctrl
1592 wxSize parentSize
= m_owner
->GetSize();
1593 wxPoint myPos
= m_text
->GetPosition();
1594 wxSize mySize
= m_text
->GetSize();
1596 m_text
->GetTextExtent(m_text
->GetValue() + _T("MM"), &sx
, &sy
);
1597 if (myPos
.x
+ sx
> parentSize
.x
)
1598 sx
= parentSize
.x
- myPos
.x
;
1601 m_text
->SetSize(sx
, wxDefaultCoord
);
1606 void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent
&event
)
1608 if ( !m_finished
&& !m_aboutToFinish
)
1611 //if ( !AcceptChanges() )
1612 // m_owner->OnRenameCancelled( m_itemEdited );
1617 // We must let the native text control handle focus
1621 bool wxDataViewTextCtrlWrapper::AcceptChanges()
1623 const wxString value
= m_text
->GetValue();
1625 if ( value
== m_startValue
)
1626 // nothing changed, always accept
1629 // if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
1630 // vetoed by the user
1633 // accepted, do rename the item
1636 m_model
->SetValue( variant
, m_col
, m_row
);
1637 m_model
->ValueChanged( m_col
, m_row
);
1642 void wxDataViewTextCtrlWrapper::Finish()
1648 m_text
->RemoveEventHandler(this);
1649 m_owner
->FinishEditing(m_text
);
1652 wxPendingDelete
.Append( this );
1656 //-----------------------------------------------------------------------------
1657 // wxDataViewMainWindow
1658 //-----------------------------------------------------------------------------
1660 int LINKAGEMODE
wxDataViewSelectionCmp( unsigned int row1
, unsigned int row2
)
1662 if (row1
> row2
) return 1;
1663 if (row1
== row2
) return 0;
1668 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
)
1670 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
)
1671 EVT_PAINT (wxDataViewMainWindow::OnPaint
)
1672 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse
)
1673 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus
)
1674 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus
)
1675 EVT_CHAR (wxDataViewMainWindow::OnChar
)
1678 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl
*parent
, wxWindowID id
,
1679 const wxPoint
&pos
, const wxSize
&size
, const wxString
&name
) :
1680 wxWindow( parent
, id
, pos
, size
, wxWANTS_CHARS
, name
),
1681 m_selection( wxDataViewSelectionCmp
)
1686 m_lastOnSame
= false;
1687 m_renameTimer
= new wxDataViewRenameTimer( this );
1688 m_textctrlWrapper
= NULL
;
1690 // TODO: user better initial values/nothing selected
1691 m_currentCol
= NULL
;
1694 // TODO: we need to calculate this smartly
1701 wxASSERT(m_lineHeight
> 2*PADDING_TOPBOTTOM
);
1704 m_dragStart
= wxPoint(0,0);
1705 m_lineLastClicked
= (unsigned int) -1;
1706 m_lineBeforeLastClicked
= (unsigned int) -1;
1707 m_lineSelectSingleOnUp
= (unsigned int) -1;
1711 SetBackgroundStyle( wxBG_STYLE_CUSTOM
);
1712 SetBackgroundColour( *wxWHITE
);
1714 m_penRule
= wxPen(GetRuleColour(), 1, wxSOLID
);
1719 wxDataViewMainWindow::~wxDataViewMainWindow()
1721 delete m_renameTimer
;
1724 void wxDataViewMainWindow::OnRenameTimer()
1726 // We have to call this here because changes may just have
1727 // been made and no screen update taken place.
1733 unsigned int cols
= GetOwner()->GetColumnCount();
1735 for (i
= 0; i
< cols
; i
++)
1737 wxDataViewColumn
*c
= GetOwner()->GetColumn( i
);
1739 continue; // skip it!
1741 if (c
== m_currentCol
)
1743 xpos
+= c
->GetWidth();
1745 wxRect
labelRect( xpos
, m_currentRow
* m_lineHeight
,
1746 m_currentCol
->GetWidth(), m_lineHeight
);
1748 wxClassInfo
*textControlClass
= CLASSINFO(wxTextCtrl
);
1750 wxTextCtrl
* const text
= (wxTextCtrl
*)textControlClass
->CreateObject();
1751 m_textctrlWrapper
= new wxDataViewTextCtrlWrapper(this, text
, GetOwner()->GetModel(),
1752 m_currentCol
->GetModelColumn(), m_currentRow
, labelRect
);
1755 void wxDataViewMainWindow::FinishEditing( wxTextCtrl
*text
)
1758 m_textctrlWrapper
= NULL
;
1760 // SetFocusIgnoringChildren();
1763 bool wxDataViewMainWindow::RowAppended()
1768 bool wxDataViewMainWindow::RowPrepended()
1773 bool wxDataViewMainWindow::RowInserted( unsigned int WXUNUSED(before
) )
1778 bool wxDataViewMainWindow::RowDeleted( unsigned int WXUNUSED(row
) )
1783 bool wxDataViewMainWindow::RowChanged( unsigned int WXUNUSED(row
) )
1788 bool wxDataViewMainWindow::ValueChanged( unsigned int WXUNUSED(col
), unsigned int row
)
1790 // NOTE: to be valid, we cannot use e.g. INT_MAX - 1
1791 #define MAX_VIRTUAL_WIDTH 100000
1793 wxRect
rect( 0, row
*m_lineHeight
, MAX_VIRTUAL_WIDTH
, m_lineHeight
);
1794 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
1795 Refresh( true, &rect
);
1800 bool wxDataViewMainWindow::RowsReordered( unsigned int *WXUNUSED(new_order
) )
1807 bool wxDataViewMainWindow::Cleared()
1812 void wxDataViewMainWindow::UpdateDisplay()
1817 void wxDataViewMainWindow::OnInternalIdle()
1819 wxWindow::OnInternalIdle();
1823 RecalculateDisplay();
1828 void wxDataViewMainWindow::RecalculateDisplay()
1830 wxDataViewListModel
*model
= GetOwner()->GetModel();
1837 int width
= GetEndOfLastCol();
1838 int height
= model
->GetRowCount() * m_lineHeight
;
1840 SetVirtualSize( width
, height
);
1841 GetOwner()->SetScrollRate( 10, m_lineHeight
);
1846 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
1848 wxWindow::ScrollWindow( dx
, dy
, rect
);
1850 if (GetOwner()->m_headerArea
)
1851 GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 );
1854 void wxDataViewMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1856 wxDataViewListModel
*model
= GetOwner()->GetModel();
1857 wxAutoBufferedPaintDC
dc( this );
1860 dc
.SetBackground(GetBackgroundColour());
1862 GetOwner()->PrepareDC( dc
);
1863 dc
.SetFont( GetFont() );
1865 wxRect update
= GetUpdateRegion().GetBox();
1866 m_owner
->CalcUnscrolledPosition( update
.x
, update
.y
, &update
.x
, &update
.y
);
1868 // compute which items needs to be redrawn
1869 unsigned int item_start
= wxMax( 0, (update
.y
/ m_lineHeight
) );
1870 unsigned int item_count
=
1871 wxMin( (int)(((update
.y
+ update
.height
) / m_lineHeight
) - item_start
+ 1),
1872 (int)(model
->GetRowCount() - item_start
) );
1873 unsigned int item_last
= item_start
+ item_count
;
1875 // compute which columns needs to be redrawn
1876 unsigned int cols
= GetOwner()->GetColumnCount();
1877 unsigned int col_start
= 0;
1878 unsigned int x_start
= 0;
1879 for (x_start
= 0; col_start
< cols
; col_start
++)
1881 wxDataViewColumn
*col
= GetOwner()->GetColumn(col_start
);
1882 if (col
->IsHidden())
1883 continue; // skip it!
1885 unsigned int w
= col
->GetWidth();
1886 if (x_start
+w
>= (unsigned int)update
.x
)
1892 unsigned int col_last
= col_start
;
1893 unsigned int x_last
= x_start
;
1894 for (; col_last
< cols
; col_last
++)
1896 wxDataViewColumn
*col
= GetOwner()->GetColumn(col_last
);
1897 if (col
->IsHidden())
1898 continue; // skip it!
1900 if (x_last
> (unsigned int)update
.GetRight())
1903 x_last
+= col
->GetWidth();
1906 // Draw horizontal rules if required
1907 if ( m_owner
->HasFlag(wxDV_HORIZ_RULES
) )
1909 dc
.SetPen(m_penRule
);
1910 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1912 for (unsigned int i
= item_start
; i
<= item_last
+1; i
++)
1914 int y
= i
* m_lineHeight
;
1915 dc
.DrawLine(x_start
, y
, x_last
, y
);
1919 // Draw vertical rules if required
1920 if ( m_owner
->HasFlag(wxDV_VERT_RULES
) )
1922 dc
.SetPen(m_penRule
);
1923 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1926 for (unsigned int i
= col_start
; i
< col_last
; i
++)
1928 wxDataViewColumn
*col
= GetOwner()->GetColumn(i
);
1929 if (col
->IsHidden())
1930 continue; // skip it
1932 dc
.DrawLine(x
, item_start
* m_lineHeight
,
1933 x
, item_last
* m_lineHeight
);
1935 x
+= col
->GetWidth();
1938 // Draw last vertical rule
1939 dc
.DrawLine(x
, item_start
* m_lineHeight
,
1940 x
, item_last
* m_lineHeight
);
1943 // redraw the background for the items which are selected/current
1944 for (unsigned int item
= item_start
; item
< item_last
; item
++)
1946 bool selected
= m_selection
.Index( item
) != wxNOT_FOUND
;
1947 if (selected
|| item
== m_currentRow
)
1949 int flags
= selected
? wxCONTROL_SELECTED
: 0;
1950 if (item
== m_currentRow
)
1951 flags
|= wxCONTROL_CURRENT
;
1953 flags
|= wxCONTROL_FOCUSED
;
1955 wxRect
rect( x_start
, item
*m_lineHeight
, x_last
, m_lineHeight
);
1956 wxRendererNative::Get().DrawItemSelectionRect
1966 // redraw all cells for all rows which must be repainted and for all columns
1968 cell_rect
.x
= x_start
;
1969 cell_rect
.height
= m_lineHeight
; // -1 is for the horizontal rules
1970 for (unsigned int i
= col_start
; i
< col_last
; i
++)
1972 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
1973 wxDataViewRenderer
*cell
= col
->GetRenderer();
1974 cell_rect
.width
= col
->GetWidth();
1976 if (col
->IsHidden())
1977 continue; // skipt it!
1979 for (unsigned int item
= item_start
; item
< item_last
; item
++)
1981 // get the cell value and set it into the renderer
1983 model
->GetValue( value
, col
->GetModelColumn(), item
);
1984 cell
->SetValue( value
);
1986 // update the y offset
1987 cell_rect
.y
= item
* m_lineHeight
;
1989 // cannot be bigger than allocated space
1990 wxSize size
= cell
->GetSize();
1991 size
.x
= wxMin( size
.x
+ 2*PADDING_RIGHTLEFT
, cell_rect
.width
);
1992 size
.y
= wxMin( size
.y
+ 2*PADDING_TOPBOTTOM
, cell_rect
.height
);
1994 wxRect
item_rect(cell_rect
.GetTopLeft(), size
);
1995 int align
= cell
->GetAlignment();
1997 // horizontal alignment:
1998 item_rect
.x
= cell_rect
.x
;
1999 if (align
& wxALIGN_CENTER_HORIZONTAL
)
2000 item_rect
.x
= cell_rect
.x
+ (cell_rect
.width
/ 2) - (size
.x
/ 2);
2001 else if (align
& wxALIGN_RIGHT
)
2002 item_rect
.x
= cell_rect
.x
+ cell_rect
.width
- size
.x
;
2003 //else: wxALIGN_LEFT is the default
2005 // vertical alignment:
2006 item_rect
.y
= cell_rect
.y
;
2007 if (align
& wxALIGN_CENTER_VERTICAL
)
2008 item_rect
.y
= cell_rect
.y
+ (cell_rect
.height
/ 2) - (size
.y
/ 2);
2009 else if (align
& wxALIGN_BOTTOM
)
2010 item_rect
.y
= cell_rect
.y
+ cell_rect
.height
- size
.y
;
2011 //else: wxALIGN_TOP is the default
2014 item_rect
.x
+= PADDING_RIGHTLEFT
;
2015 item_rect
.y
+= PADDING_TOPBOTTOM
;
2016 item_rect
.width
= size
.x
- 2 * PADDING_RIGHTLEFT
;
2017 item_rect
.height
= size
.y
- 2 * PADDING_TOPBOTTOM
;
2020 if (m_selection
.Index(item
) != wxNOT_FOUND
)
2021 state
|= wxDATAVIEW_CELL_SELECTED
;
2023 // TODO: it would be much more efficient to create a clipping
2024 // region for the entire column being rendered (in the OnPaint
2025 // of wxDataViewMainWindow) instead of a single clip region for
2026 // each cell. However it would mean that each renderer should
2027 // respect the given wxRect's top & bottom coords, eventually
2028 // violating only the left & right coords - however the user can
2029 // make its own renderer and thus we cannot be sure of that.
2030 dc
.SetClippingRegion( item_rect
);
2031 cell
->Render( item_rect
, &dc
, state
);
2032 dc
.DestroyClippingRegion();
2035 cell_rect
.x
+= cell_rect
.width
;
2039 int wxDataViewMainWindow::GetCountPerPage() const
2041 wxSize size
= GetClientSize();
2042 return size
.y
/ m_lineHeight
;
2045 int wxDataViewMainWindow::GetEndOfLastCol() const
2049 for (i
= 0; i
< GetOwner()->GetColumnCount(); i
++)
2051 const wxDataViewColumn
*c
=
2052 wx_const_cast(wxDataViewCtrl
*, GetOwner())->GetColumn( i
);
2055 width
+= c
->GetWidth();
2060 unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const
2064 m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y
);
2066 return y
/ m_lineHeight
;
2069 unsigned int wxDataViewMainWindow::GetLastVisibleRow() const
2071 wxSize client_size
= GetClientSize();
2072 m_owner
->CalcUnscrolledPosition( client_size
.x
, client_size
.y
,
2073 &client_size
.x
, &client_size
.y
);
2075 return wxMin( GetRowCount()-1, ((unsigned)client_size
.y
/m_lineHeight
)+1 );
2078 unsigned int wxDataViewMainWindow::GetRowCount() const
2080 return wx_const_cast(wxDataViewCtrl
*, GetOwner())->GetModel()->GetRowCount();
2083 void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row
)
2090 void wxDataViewMainWindow::SelectAllRows( bool on
)
2097 m_selection
.Clear();
2098 for (unsigned int i
= 0; i
< GetRowCount(); i
++)
2099 m_selection
.Add( i
);
2104 unsigned int first_visible
= GetFirstVisibleRow();
2105 unsigned int last_visible
= GetLastVisibleRow();
2107 for (i
= 0; i
< m_selection
.GetCount(); i
++)
2109 unsigned int row
= m_selection
[i
];
2110 if ((row
>= first_visible
) && (row
<= last_visible
))
2113 m_selection
.Clear();
2117 void wxDataViewMainWindow::SelectRow( unsigned int row
, bool on
)
2119 if (m_selection
.Index( row
) == wxNOT_FOUND
)
2123 m_selection
.Add( row
);
2131 m_selection
.Remove( row
);
2137 void wxDataViewMainWindow::SelectRows( unsigned int from
, unsigned int to
, bool on
)
2141 unsigned int tmp
= from
;
2147 for (i
= from
; i
<= to
; i
++)
2149 if (m_selection
.Index( i
) == wxNOT_FOUND
)
2152 m_selection
.Add( i
);
2157 m_selection
.Remove( i
);
2160 RefreshRows( from
, to
);
2163 void wxDataViewMainWindow::Select( const wxArrayInt
& aSelections
)
2165 for (size_t i
=0; i
< aSelections
.GetCount(); i
++)
2167 int n
= aSelections
[i
];
2169 m_selection
.Add( n
);
2174 void wxDataViewMainWindow::ReverseRowSelection( unsigned int row
)
2176 if (m_selection
.Index( row
) == wxNOT_FOUND
)
2177 m_selection
.Add( row
);
2179 m_selection
.Remove( row
);
2183 bool wxDataViewMainWindow::IsRowSelected( unsigned int row
)
2185 return (m_selection
.Index( row
) != wxNOT_FOUND
);
2188 void wxDataViewMainWindow::RefreshRow( unsigned int row
)
2190 wxRect
rect( 0, row
*m_lineHeight
, GetEndOfLastCol(), m_lineHeight
);
2191 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2193 wxSize client_size
= GetClientSize();
2194 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
2195 wxRect intersect_rect
= client_rect
.Intersect( rect
);
2196 if (intersect_rect
.width
> 0)
2197 Refresh( true, &intersect_rect
);
2200 void wxDataViewMainWindow::RefreshRows( unsigned int from
, unsigned int to
)
2204 unsigned int tmp
= to
;
2209 wxRect
rect( 0, from
*m_lineHeight
, GetEndOfLastCol(), (to
-from
+1) * m_lineHeight
);
2210 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2212 wxSize client_size
= GetClientSize();
2213 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
2214 wxRect intersect_rect
= client_rect
.Intersect( rect
);
2215 if (intersect_rect
.width
> 0)
2216 Refresh( true, &intersect_rect
);
2219 void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow
)
2221 unsigned int count
= GetRowCount();
2222 if (firstRow
> count
)
2225 wxRect
rect( 0, firstRow
*m_lineHeight
, GetEndOfLastCol(), count
* m_lineHeight
);
2226 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2228 wxSize client_size
= GetClientSize();
2229 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
2230 wxRect intersect_rect
= client_rect
.Intersect( rect
);
2231 if (intersect_rect
.width
> 0)
2232 Refresh( true, &intersect_rect
);
2235 void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
)
2237 wxCHECK_RET( newCurrent
< GetRowCount(),
2238 _T("invalid item index in OnArrowChar()") );
2240 // if there is no selection, we cannot move it anywhere
2241 if (!HasCurrentRow())
2244 unsigned int oldCurrent
= m_currentRow
;
2246 // in single selection we just ignore Shift as we can't select several
2248 if ( event
.ShiftDown() && !IsSingleSel() )
2250 RefreshRow( oldCurrent
);
2252 ChangeCurrentRow( newCurrent
);
2254 // select all the items between the old and the new one
2255 if ( oldCurrent
> newCurrent
)
2257 newCurrent
= oldCurrent
;
2258 oldCurrent
= m_currentRow
;
2261 SelectRows( oldCurrent
, newCurrent
, true );
2265 RefreshRow( oldCurrent
);
2267 // all previously selected items are unselected unless ctrl is held
2268 if ( !event
.ControlDown() )
2269 SelectAllRows(false);
2271 ChangeCurrentRow( newCurrent
);
2273 if ( !event
.ControlDown() )
2274 SelectRow( m_currentRow
, true );
2276 RefreshRow( m_currentRow
);
2279 //EnsureVisible( m_currentRow );
2282 wxRect
wxDataViewMainWindow::GetLineRect( unsigned int row
) const
2286 rect
.y
= m_lineHeight
* row
;
2287 rect
.width
= GetEndOfLastCol();
2288 rect
.height
= m_lineHeight
;
2293 void wxDataViewMainWindow::OnChar( wxKeyEvent
&event
)
2295 if (event
.GetKeyCode() == WXK_TAB
)
2297 wxNavigationKeyEvent nevent
;
2298 nevent
.SetWindowChange( event
.ControlDown() );
2299 nevent
.SetDirection( !event
.ShiftDown() );
2300 nevent
.SetEventObject( GetParent()->GetParent() );
2301 nevent
.SetCurrentFocus( m_parent
);
2302 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
))
2306 // no item -> nothing to do
2307 if (!HasCurrentRow())
2313 // don't use m_linesPerPage directly as it might not be computed yet
2314 const int pageSize
= GetCountPerPage();
2315 wxCHECK_RET( pageSize
, _T("should have non zero page size") );
2317 switch ( event
.GetKeyCode() )
2320 if ( m_currentRow
> 0 )
2321 OnArrowChar( m_currentRow
- 1, event
);
2325 if ( m_currentRow
< GetRowCount() - 1 )
2326 OnArrowChar( m_currentRow
+ 1, event
);
2331 OnArrowChar( GetRowCount() - 1, event
);
2336 OnArrowChar( 0, event
);
2341 int steps
= pageSize
- 1;
2342 int index
= m_currentRow
- steps
;
2346 OnArrowChar( index
, event
);
2352 int steps
= pageSize
- 1;
2353 unsigned int index
= m_currentRow
+ steps
;
2354 unsigned int count
= GetRowCount();
2355 if ( index
>= count
)
2358 OnArrowChar( index
, event
);
2367 void wxDataViewMainWindow::OnMouse( wxMouseEvent
&event
)
2369 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
2371 // let the base handle mouse wheel events.
2376 int x
= event
.GetX();
2377 int y
= event
.GetY();
2378 m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y
);
2380 wxDataViewColumn
*col
= NULL
;
2383 unsigned int cols
= GetOwner()->GetColumnCount();
2385 for (i
= 0; i
< cols
; i
++)
2387 wxDataViewColumn
*c
= GetOwner()->GetColumn( i
);
2389 continue; // skip it!
2391 if (x
< xpos
+ c
->GetWidth())
2396 xpos
+= c
->GetWidth();
2400 wxDataViewRenderer
*cell
= col
->GetRenderer();
2402 unsigned int current
= y
/ m_lineHeight
;
2404 if ((current
> GetRowCount()) || (x
> GetEndOfLastCol()))
2406 // Unselect all if below the last row ?
2410 wxDataViewListModel
*model
= GetOwner()->GetModel();
2412 if (event
.Dragging())
2414 if (m_dragCount
== 0)
2416 // we have to report the raw, physical coords as we want to be
2417 // able to call HitTest(event.m_pointDrag) from the user code to
2418 // get the item being dragged
2419 m_dragStart
= event
.GetPosition();
2424 if (m_dragCount
!= 3)
2427 if (event
.LeftIsDown())
2429 // Notify cell about drag
2438 bool forceClick
= false;
2440 if (event
.ButtonDClick())
2442 m_renameTimer
->Stop();
2443 m_lastOnSame
= false;
2446 if (event
.LeftDClick())
2448 if ( current
== m_lineLastClicked
)
2450 if (cell
->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE
)
2453 model
->GetValue( value
, col
->GetModelColumn(), current
);
2454 cell
->SetValue( value
);
2455 wxRect
cell_rect( xpos
, current
* m_lineHeight
,
2456 col
->GetWidth(), m_lineHeight
);
2457 cell
->Activate( cell_rect
, model
, col
->GetModelColumn(), current
);
2463 // The first click was on another item, so don't interpret this as
2464 // a double click, but as a simple click instead
2471 if (m_lineSelectSingleOnUp
!= (unsigned int)-1)
2473 // select single line
2474 SelectAllRows( false );
2475 SelectRow( m_lineSelectSingleOnUp
, true );
2480 if ((col
== m_currentCol
) && (current
== m_currentRow
) &&
2481 (cell
->GetMode() == wxDATAVIEW_CELL_EDITABLE
) )
2483 m_renameTimer
->Start( 100, true );
2487 m_lastOnSame
= false;
2488 m_lineSelectSingleOnUp
= (unsigned int)-1;
2492 // This is necessary, because after a DnD operation in
2493 // from and to ourself, the up event is swallowed by the
2494 // DnD code. So on next non-up event (which means here and
2495 // now) m_lineSelectSingleOnUp should be reset.
2496 m_lineSelectSingleOnUp
= (unsigned int)-1;
2499 if (event
.RightDown())
2501 m_lineBeforeLastClicked
= m_lineLastClicked
;
2502 m_lineLastClicked
= current
;
2504 // If the item is already selected, do not update the selection.
2505 // Multi-selections should not be cleared if a selected item is clicked.
2506 if (!IsRowSelected(current
))
2508 SelectAllRows(false);
2509 ChangeCurrentRow(current
);
2510 SelectRow(m_currentRow
,true);
2513 // notify cell about right click
2516 // Allow generation of context menu event
2519 else if (event
.MiddleDown())
2521 // notify cell about middle click
2524 if (event
.LeftDown() || forceClick
)
2530 m_lineBeforeLastClicked
= m_lineLastClicked
;
2531 m_lineLastClicked
= current
;
2533 unsigned int oldCurrentRow
= m_currentRow
;
2534 bool oldWasSelected
= IsRowSelected(m_currentRow
);
2536 bool cmdModifierDown
= event
.CmdDown();
2537 if ( IsSingleSel() || !(cmdModifierDown
|| event
.ShiftDown()) )
2539 if ( IsSingleSel() || !IsRowSelected(current
) )
2541 SelectAllRows( false );
2543 ChangeCurrentRow(current
);
2545 SelectRow(m_currentRow
,true);
2547 else // multi sel & current is highlighted & no mod keys
2549 m_lineSelectSingleOnUp
= current
;
2550 ChangeCurrentRow(current
); // change focus
2553 else // multi sel & either ctrl or shift is down
2555 if (cmdModifierDown
)
2557 ChangeCurrentRow(current
);
2559 ReverseRowSelection(m_currentRow
);
2561 else if (event
.ShiftDown())
2563 ChangeCurrentRow(current
);
2565 unsigned int lineFrom
= oldCurrentRow
,
2568 if ( lineTo
< lineFrom
)
2571 lineFrom
= m_currentRow
;
2574 SelectRows(lineFrom
, lineTo
, true);
2576 else // !ctrl, !shift
2578 // test in the enclosing if should make it impossible
2579 wxFAIL_MSG( _T("how did we get here?") );
2583 if (m_currentRow
!= oldCurrentRow
)
2584 RefreshRow( oldCurrentRow
);
2586 wxDataViewColumn
*oldCurrentCol
= m_currentCol
;
2588 // Update selection here...
2591 m_lastOnSame
= !forceClick
&& ((col
== oldCurrentCol
) &&
2592 (current
== oldCurrentRow
)) && oldWasSelected
;
2596 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent
&event
)
2600 if (HasCurrentRow())
2606 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent
&event
)
2610 if (HasCurrentRow())
2616 //-----------------------------------------------------------------------------
2618 //-----------------------------------------------------------------------------
2620 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
)
2622 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
)
2623 EVT_SIZE(wxDataViewCtrl::OnSize
)
2626 wxDataViewCtrl::~wxDataViewCtrl()
2629 GetModel()->RemoveNotifier( m_notifier
);
2632 void wxDataViewCtrl::Init()
2637 bool wxDataViewCtrl::Create(wxWindow
*parent
, wxWindowID id
,
2638 const wxPoint
& pos
, const wxSize
& size
,
2639 long style
, const wxValidator
& validator
)
2641 if (!wxControl::Create( parent
, id
, pos
, size
,
2642 style
| wxScrolledWindowStyle
|wxSUNKEN_BORDER
, validator
))
2648 MacSetClipChildren( true ) ;
2651 m_clientArea
= new wxDataViewMainWindow( this, wxID_ANY
);
2653 if (HasFlag(wxDV_NO_HEADER
))
2654 m_headerArea
= NULL
;
2656 m_headerArea
= new wxDataViewHeaderWindow( this, wxID_ANY
);
2658 SetTargetWindow( m_clientArea
);
2660 wxBoxSizer
*sizer
= new wxBoxSizer( wxVERTICAL
);
2662 sizer
->Add( m_headerArea
, 0, wxGROW
);
2663 sizer
->Add( m_clientArea
, 1, wxGROW
);
2670 WXLRESULT
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
,
2674 WXLRESULT rc
= wxDataViewCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
);
2677 // we need to process arrows ourselves for scrolling
2678 if ( nMsg
== WM_GETDLGCODE
)
2680 rc
|= DLGC_WANTARROWS
;
2688 void wxDataViewCtrl::OnSize( wxSizeEvent
&WXUNUSED(event
) )
2690 // We need to override OnSize so that our scrolled
2691 // window a) does call Layout() to use sizers for
2692 // positioning the controls but b) does not query
2693 // the sizer for their size and use that for setting
2694 // the scrollable area as set that ourselves by
2695 // calling SetScrollbar() further down.
2702 bool wxDataViewCtrl::AssociateModel( wxDataViewListModel
*model
)
2704 if (!wxDataViewCtrlBase::AssociateModel( model
))
2707 m_notifier
= new wxGenericDataViewListModelNotifier( m_clientArea
);
2709 model
->AddNotifier( m_notifier
);
2711 m_clientArea
->UpdateDisplay();
2716 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn
*col
)
2718 if (!wxDataViewCtrlBase::AppendColumn(col
))
2725 void wxDataViewCtrl::OnColumnChange()
2728 m_headerArea
->UpdateDisplay();
2730 m_clientArea
->UpdateDisplay();
2733 void wxDataViewCtrl::SetSelection( int row
)
2735 m_clientArea
->SelectRow(row
, true);
2738 void wxDataViewCtrl::SetSelectionRange( unsigned int from
, unsigned int to
)
2740 m_clientArea
->SelectRows(from
, to
, true);
2743 void wxDataViewCtrl::SetSelections( const wxArrayInt
& aSelections
)
2745 m_clientArea
->Select(aSelections
);
2748 void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row
) )
2753 bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row
) ) const
2760 int wxDataViewCtrl::GetSelection() const
2767 int wxDataViewCtrl::GetSelections(wxArrayInt
& WXUNUSED(aSelections
) ) const
2775 // !wxUSE_GENERICDATAVIEWCTRL
2778 // wxUSE_DATAVIEWCTRL