Added enabling/disabling of cell edit control.
[wxWidgets.git] / src / generic / grid.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 // Name: grid.cpp
3 // Purpose: wxGrid and related classes
4 // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
5 // Modified by:
6 // Created: 1/08/1999
7 // RCS-ID: $Id$
8 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "grid.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx/wx.h".
25 #include "wx/wxprec.h"
26
27 #include "wx/defs.h"
28
29 #ifdef __BORLANDC__
30 #pragma hdrstop
31 #endif
32
33 #if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
34 #include "gridg.cpp"
35 #else
36
37 #ifndef WX_PRECOMP
38 #include "wx/utils.h"
39 #include "wx/dcclient.h"
40 #include "wx/settings.h"
41 #include "wx/log.h"
42 #endif
43
44 // this include needs to be outside precomp for BCC
45 #include "wx/textfile.h"
46
47 #include "wx/generic/grid.h"
48
49 // ----------------------------------------------------------------------------
50 // array classes
51 // ----------------------------------------------------------------------------
52
53 WX_DEFINE_ARRAY(wxGridCellAttr *, wxArrayAttrs);
54
55 struct wxGridCellWithAttr
56 {
57 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
58 : coords(row, col), attr(attr_)
59 {
60 }
61
62 ~wxGridCellWithAttr()
63 {
64 attr->DecRef();
65 }
66
67 wxGridCellCoords coords;
68 wxGridCellAttr *attr;
69 };
70
71 WX_DECLARE_OBJARRAY(wxGridCellWithAttr, wxGridCellWithAttrArray);
72
73 #include "wx/arrimpl.cpp"
74
75 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
76 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
77
78 // ----------------------------------------------------------------------------
79 // private classes
80 // ----------------------------------------------------------------------------
81
82 class WXDLLEXPORT wxGridRowLabelWindow : public wxWindow
83 {
84 public:
85 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
86 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
87 const wxPoint &pos, const wxSize &size );
88
89 private:
90 wxGrid *m_owner;
91
92 void OnPaint( wxPaintEvent& event );
93 void OnMouseEvent( wxMouseEvent& event );
94 void OnKeyDown( wxKeyEvent& event );
95
96 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
97 DECLARE_EVENT_TABLE()
98 };
99
100
101 class WXDLLEXPORT wxGridColLabelWindow : public wxWindow
102 {
103 public:
104 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
105 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
106 const wxPoint &pos, const wxSize &size );
107
108 private:
109 wxGrid *m_owner;
110
111 void OnPaint( wxPaintEvent &event );
112 void OnMouseEvent( wxMouseEvent& event );
113 void OnKeyDown( wxKeyEvent& event );
114
115 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
116 DECLARE_EVENT_TABLE()
117 };
118
119
120 class WXDLLEXPORT wxGridCornerLabelWindow : public wxWindow
121 {
122 public:
123 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
124 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
125 const wxPoint &pos, const wxSize &size );
126
127 private:
128 wxGrid *m_owner;
129
130 void OnMouseEvent( wxMouseEvent& event );
131 void OnKeyDown( wxKeyEvent& event );
132 void OnPaint( wxPaintEvent& event );
133
134 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
135 DECLARE_EVENT_TABLE()
136 };
137
138 class WXDLLEXPORT wxGridWindow : public wxPanel
139 {
140 public:
141 wxGridWindow()
142 {
143 m_owner = (wxGrid *)NULL;
144 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
145 m_colLabelWin = (wxGridColLabelWindow *)NULL;
146 }
147
148 wxGridWindow( wxGrid *parent,
149 wxGridRowLabelWindow *rowLblWin,
150 wxGridColLabelWindow *colLblWin,
151 wxWindowID id, const wxPoint &pos, const wxSize &size );
152 ~wxGridWindow();
153
154 void ScrollWindow( int dx, int dy, const wxRect *rect );
155
156 private:
157 wxGrid *m_owner;
158 wxGridRowLabelWindow *m_rowLabelWin;
159 wxGridColLabelWindow *m_colLabelWin;
160
161 void OnPaint( wxPaintEvent &event );
162 void OnMouseEvent( wxMouseEvent& event );
163 void OnKeyDown( wxKeyEvent& );
164 void OnEraseBackground( wxEraseEvent& );
165
166
167 DECLARE_DYNAMIC_CLASS(wxGridWindow)
168 DECLARE_EVENT_TABLE()
169 };
170
171
172
173 class wxGridCellEditorEvtHandler : public wxEvtHandler
174 {
175 public:
176 wxGridCellEditorEvtHandler()
177 : m_grid(0), m_editor(0)
178 { }
179 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
180 : m_grid(grid), m_editor(editor)
181 { }
182
183 void OnKeyDown(wxKeyEvent& event);
184
185 private:
186 wxGrid* m_grid;
187 wxGridCellEditor* m_editor;
188 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
189 DECLARE_EVENT_TABLE()
190 };
191
192
193 IMPLEMENT_DYNAMIC_CLASS( wxGridCellEditorEvtHandler, wxEvtHandler )
194 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
195 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
196 END_EVENT_TABLE()
197
198
199
200 // ----------------------------------------------------------------------------
201 // the internal data representation used by wxGridCellAttrProvider
202 // ----------------------------------------------------------------------------
203
204 // this class stores attributes set for cells
205 class WXDLLEXPORT wxGridCellAttrData
206 {
207 public:
208 void SetAttr(wxGridCellAttr *attr, int row, int col);
209 wxGridCellAttr *GetAttr(int row, int col) const;
210
211 private:
212 // searches for the attr for given cell, returns wxNOT_FOUND if not found
213 int FindIndex(int row, int col) const;
214
215 wxGridCellWithAttrArray m_attrs;
216 };
217
218 // this class stores attributes set for rows or columns
219 class WXDLLEXPORT wxGridRowOrColAttrData
220 {
221 public:
222 ~wxGridRowOrColAttrData();
223
224 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
225 wxGridCellAttr *GetAttr(int rowOrCol) const;
226
227 private:
228 wxArrayInt m_rowsOrCols;
229 wxArrayAttrs m_attrs;
230 };
231
232 // NB: this is just a wrapper around 3 objects: one which stores cell
233 // attributes, and 2 others for row/col ones
234 class WXDLLEXPORT wxGridCellAttrProviderData
235 {
236 public:
237 wxGridCellAttrData m_cellAttrs;
238 wxGridRowOrColAttrData m_rowAttrs,
239 m_colAttrs;
240 };
241
242 // ----------------------------------------------------------------------------
243 // conditional compilation
244 // ----------------------------------------------------------------------------
245
246 #ifndef WXGRID_DRAW_LINES
247 #define WXGRID_DRAW_LINES 1
248 #endif
249
250 // ----------------------------------------------------------------------------
251 // globals
252 // ----------------------------------------------------------------------------
253
254 //#define DEBUG_ATTR_CACHE
255 #ifdef DEBUG_ATTR_CACHE
256 static size_t gs_nAttrCacheHits = 0;
257 static size_t gs_nAttrCacheMisses = 0;
258 #endif // DEBUG_ATTR_CACHE
259
260 wxGridCellCoords wxGridNoCellCoords( -1, -1 );
261 wxRect wxGridNoCellRect( -1, -1, -1, -1 );
262
263 // scroll line size
264 // TODO: fixed so far - make configurable later (and also different for x/y)
265 static const size_t GRID_SCROLL_LINE = 10;
266
267 // ============================================================================
268 // implementation
269 // ============================================================================
270
271
272 // ----------------------------------------------------------------------------
273 // wxGridCellEditor
274 // ----------------------------------------------------------------------------
275
276 wxGridCellEditor::wxGridCellEditor()
277 {
278 m_control = NULL;
279 }
280
281
282 wxGridCellEditor::~wxGridCellEditor()
283 {
284 Destroy();
285 }
286
287
288 void wxGridCellEditor::Destroy()
289 {
290 if (m_control) {
291 m_control->Destroy();
292 m_control = NULL;
293 }
294 }
295
296 void wxGridCellEditor::Show(bool show)
297 {
298 wxASSERT_MSG(m_control,
299 wxT("The wxGridCellEditor must be Created first!"));
300 m_control->Show(show);
301 }
302
303 void wxGridCellEditor::SetSize(const wxRect& rect)
304 {
305 wxASSERT_MSG(m_control,
306 wxT("The wxGridCellEditor must be Created first!"));
307 m_control->SetSize(rect);
308 }
309
310 void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
311 {
312 event.Skip();
313 }
314
315
316 wxGridCellTextEditor::wxGridCellTextEditor()
317 {
318 }
319
320 void wxGridCellTextEditor::Create(wxWindow* parent,
321 wxWindowID id,
322 const wxPoint& pos,
323 const wxSize& size,
324 wxEvtHandler* evtHandler)
325 {
326 m_control = new wxTextCtrl(parent, -1, "", pos, size
327 #if defined(__WXMSW__)
328 , wxTE_MULTILINE | wxTE_NO_VSCROLL
329 #endif
330 );
331
332 if (evtHandler)
333 m_control->PushEventHandler(evtHandler);
334 }
335
336
337 void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid,
338 wxGridCellAttr* attr)
339 {
340 wxASSERT_MSG(m_control,
341 wxT("The wxGridCellEditor must be Created first!"));
342
343 m_startValue = grid->GetTable()->GetValue(row, col);
344 ((wxTextCtrl*)m_control)->SetValue(m_startValue);
345 ((wxTextCtrl*)m_control)->SetInsertionPointEnd();
346 ((wxTextCtrl*)m_control)->SetFocus();
347
348 // ??? Should we use attr and try to set colours and font?
349 }
350
351
352
353 bool wxGridCellTextEditor::EndEdit(int row, int col, bool saveValue,
354 wxGrid* grid, wxGridCellAttr* attr)
355 {
356 wxASSERT_MSG(m_control,
357 wxT("The wxGridCellEditor must be Created first!"));
358
359 bool changed = FALSE;
360 wxString value = ((wxTextCtrl*)m_control)->GetValue();
361 if (value != m_startValue)
362 changed = TRUE;
363
364 if (changed)
365 grid->GetTable()->SetValue(row, col, value);
366 m_startValue = "";
367
368 return changed;
369 }
370
371
372 void wxGridCellTextEditor::Reset()
373 {
374 wxASSERT_MSG(m_control,
375 wxT("The wxGridCellEditor must be Created first!"));
376
377 ((wxTextCtrl*)m_control)->SetValue(m_startValue);
378 ((wxTextCtrl*)m_control)->SetInsertionPointEnd();
379 }
380
381 void wxGridCellTextEditor::HandleReturn(wxKeyEvent& event)
382 {
383 #if defined(__WXMOTIF__) || defined(__WXGTK__)
384 // wxMotif needs a little extra help...
385 int pos = ((wxTextCtrl*)m_control)->GetInsertionPoint();
386 wxString s( ((wxTextCtrl*)m_control)->GetValue() );
387 s = s.Left(pos) + "\n" + s.Mid(pos);
388 ((wxTextCtrl*)m_control)->SetValue(s);
389 ((wxTextCtrl*)m_control)->SetInsertionPoint( pos );
390 #else
391 // the other ports can handle a Return key press
392 //
393 event.Skip();
394 #endif
395 }
396
397
398 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
399 {
400 switch ( event.KeyCode() )
401 {
402 case WXK_ESCAPE:
403 m_editor->Reset();
404 break;
405
406 case WXK_UP:
407 case WXK_DOWN:
408 case WXK_LEFT:
409 case WXK_RIGHT:
410 case WXK_PRIOR:
411 case WXK_NEXT:
412 case WXK_SPACE:
413 // send the event to the parent grid, skipping the
414 // event if nothing happens
415 //
416 event.Skip( m_grid->ProcessEvent( event ) );
417 break;
418
419 case WXK_RETURN:
420 if (!m_grid->ProcessEvent(event))
421 m_editor->HandleReturn(event);
422 break;
423
424 case WXK_HOME:
425 case WXK_END:
426 // send the event to the parent grid, skipping the
427 // event if nothing happens
428 //
429 event.Skip( m_grid->ProcessEvent( event ) );
430 break;
431
432 default:
433 event.Skip();
434 }
435 }
436
437 // ----------------------------------------------------------------------------
438 // wxGridCellRenderer
439 // ----------------------------------------------------------------------------
440
441 void wxGridCellRenderer::Draw(wxGrid& grid,
442 wxGridCellAttr& attr,
443 wxDC& dc,
444 const wxRect& rect,
445 int row, int col,
446 bool isSelected)
447 {
448 dc.SetBackgroundMode( wxSOLID );
449
450 if ( isSelected )
451 {
452 dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
453 }
454 else
455 {
456 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
457 }
458
459 dc.SetPen( *wxTRANSPARENT_PEN );
460 dc.DrawRectangle(rect);
461 }
462
463 void wxGridCellStringRenderer::Draw(wxGrid& grid,
464 wxGridCellAttr& attr,
465 wxDC& dc,
466 const wxRect& rectCell,
467 int row, int col,
468 bool isSelected)
469 {
470 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
471
472 // now we only have to draw the text
473 dc.SetBackgroundMode( wxTRANSPARENT );
474
475 if ( isSelected )
476 {
477 dc.SetTextBackground( grid.GetSelectionBackground() );
478 dc.SetTextForeground( grid.GetSelectionForeground() );
479 }
480 else
481 {
482 dc.SetTextBackground( attr.GetBackgroundColour() );
483 dc.SetTextForeground( attr.GetTextColour() );
484 }
485 dc.SetFont( attr.GetFont() );
486
487 int hAlign, vAlign;
488 attr.GetAlignment(&hAlign, &vAlign);
489
490 wxRect rect = rectCell;
491 rect.x++;
492 rect.y++;
493 rect.width -= 2;
494 rect.height -= 2;
495
496 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
497 rect, hAlign, vAlign);
498 }
499
500 // ----------------------------------------------------------------------------
501 // wxGridCellAttr
502 // ----------------------------------------------------------------------------
503
504 const wxColour& wxGridCellAttr::GetTextColour() const
505 {
506 if (HasTextColour())
507 return m_colText;
508 else if (m_defGridAttr != this)
509 return m_defGridAttr->GetTextColour();
510 else {
511 wxFAIL_MSG(wxT("Missing default cell attribute"));
512 return wxNullColour;
513 }
514 }
515
516
517 const wxColour& wxGridCellAttr::GetBackgroundColour() const
518 {
519 if (HasBackgroundColour())
520 return m_colBack;
521 else if (m_defGridAttr != this)
522 return m_defGridAttr->GetBackgroundColour();
523 else {
524 wxFAIL_MSG(wxT("Missing default cell attribute"));
525 return wxNullColour;
526 }
527 }
528
529
530 const wxFont& wxGridCellAttr::GetFont() const
531 {
532 if (HasFont())
533 return m_font;
534 else if (m_defGridAttr != this)
535 return m_defGridAttr->GetFont();
536 else {
537 wxFAIL_MSG(wxT("Missing default cell attribute"));
538 return wxNullFont;
539 }
540 }
541
542
543 void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
544 {
545 if (HasAlignment()) {
546 if ( hAlign ) *hAlign = m_hAlign;
547 if ( vAlign ) *vAlign = m_vAlign;
548 }
549 else if (m_defGridAttr != this)
550 m_defGridAttr->GetAlignment(hAlign, vAlign);
551 else {
552 wxFAIL_MSG(wxT("Missing default cell attribute"));
553 }
554 }
555
556
557 wxGridCellRenderer* wxGridCellAttr::GetRenderer() const
558 {
559 if (HasRenderer())
560 return m_renderer;
561 else if (m_defGridAttr != this)
562 return m_defGridAttr->GetRenderer();
563 else {
564 wxFAIL_MSG(wxT("Missing default cell attribute"));
565 return NULL;
566 }
567 }
568
569 // ----------------------------------------------------------------------------
570 // wxGridCellAttrData
571 // ----------------------------------------------------------------------------
572
573 void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
574 {
575 int n = FindIndex(row, col);
576 if ( n == wxNOT_FOUND )
577 {
578 // add the attribute
579 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
580 }
581 else
582 {
583 if ( attr )
584 {
585 // change the attribute
586 m_attrs[(size_t)n].attr = attr;
587 }
588 else
589 {
590 // remove this attribute
591 m_attrs.RemoveAt((size_t)n);
592 }
593 }
594 }
595
596 wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
597 {
598 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
599
600 int n = FindIndex(row, col);
601 if ( n != wxNOT_FOUND )
602 {
603 attr = m_attrs[(size_t)n].attr;
604 attr->IncRef();
605 }
606
607 return attr;
608 }
609
610 int wxGridCellAttrData::FindIndex(int row, int col) const
611 {
612 size_t count = m_attrs.GetCount();
613 for ( size_t n = 0; n < count; n++ )
614 {
615 const wxGridCellCoords& coords = m_attrs[n].coords;
616 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
617 {
618 return n;
619 }
620 }
621
622 return wxNOT_FOUND;
623 }
624
625 // ----------------------------------------------------------------------------
626 // wxGridRowOrColAttrData
627 // ----------------------------------------------------------------------------
628
629 wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
630 {
631 size_t count = m_attrs.Count();
632 for ( size_t n = 0; n < count; n++ )
633 {
634 m_attrs[n]->DecRef();
635 }
636 }
637
638 wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
639 {
640 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
641
642 int n = m_rowsOrCols.Index(rowOrCol);
643 if ( n != wxNOT_FOUND )
644 {
645 attr = m_attrs[(size_t)n];
646 attr->IncRef();
647 }
648
649 return attr;
650 }
651
652 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
653 {
654 int n = m_rowsOrCols.Index(rowOrCol);
655 if ( n == wxNOT_FOUND )
656 {
657 // add the attribute
658 m_rowsOrCols.Add(rowOrCol);
659 m_attrs.Add(attr);
660 }
661 else
662 {
663 if ( attr )
664 {
665 // change the attribute
666 m_attrs[(size_t)n] = attr;
667 }
668 else
669 {
670 // remove this attribute
671 m_attrs[(size_t)n]->DecRef();
672 m_rowsOrCols.RemoveAt((size_t)n);
673 m_attrs.RemoveAt((size_t)n);
674 }
675 }
676 }
677
678 // ----------------------------------------------------------------------------
679 // wxGridCellAttrProvider
680 // ----------------------------------------------------------------------------
681
682 wxGridCellAttrProvider::wxGridCellAttrProvider()
683 {
684 m_data = (wxGridCellAttrProviderData *)NULL;
685 }
686
687 wxGridCellAttrProvider::~wxGridCellAttrProvider()
688 {
689 delete m_data;
690 }
691
692 void wxGridCellAttrProvider::InitData()
693 {
694 m_data = new wxGridCellAttrProviderData;
695 }
696
697 wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col) const
698 {
699 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
700 if ( m_data )
701 {
702 // first look for the attribute of this specific cell
703 attr = m_data->m_cellAttrs.GetAttr(row, col);
704
705 if ( !attr )
706 {
707 // then look for the col attr (col attributes are more common than
708 // the row ones, hence they have priority)
709 attr = m_data->m_colAttrs.GetAttr(col);
710 }
711
712 if ( !attr )
713 {
714 // finally try the row attributes
715 attr = m_data->m_rowAttrs.GetAttr(row);
716 }
717 }
718
719 return attr;
720 }
721
722 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
723 int row, int col)
724 {
725 if ( !m_data )
726 InitData();
727
728 m_data->m_cellAttrs.SetAttr(attr, row, col);
729 }
730
731 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
732 {
733 if ( !m_data )
734 InitData();
735
736 m_data->m_rowAttrs.SetAttr(attr, row);
737 }
738
739 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
740 {
741 if ( !m_data )
742 InitData();
743
744 m_data->m_colAttrs.SetAttr(attr, col);
745 }
746
747 // ----------------------------------------------------------------------------
748 // wxGridTableBase
749 // ----------------------------------------------------------------------------
750
751 //////////////////////////////////////////////////////////////////////
752 //
753 // Abstract base class for grid data (the model)
754 //
755 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
756
757
758 wxGridTableBase::wxGridTableBase()
759 {
760 m_view = (wxGrid *) NULL;
761 m_attrProvider = (wxGridCellAttrProvider *) NULL;
762 }
763
764 wxGridTableBase::~wxGridTableBase()
765 {
766 delete m_attrProvider;
767 }
768
769 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
770 {
771 delete m_attrProvider;
772 m_attrProvider = attrProvider;
773 }
774
775 wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col)
776 {
777 if ( m_attrProvider )
778 return m_attrProvider->GetAttr(row, col);
779 else
780 return (wxGridCellAttr *)NULL;
781 }
782
783 void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
784 {
785 if ( m_attrProvider )
786 {
787 m_attrProvider->SetAttr(attr, row, col);
788 }
789 else
790 {
791 // as we take ownership of the pointer and don't store it, we must
792 // free it now
793 attr->SafeDecRef();
794 }
795 }
796
797 void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
798 {
799 if ( m_attrProvider )
800 {
801 m_attrProvider->SetRowAttr(attr, row);
802 }
803 else
804 {
805 // as we take ownership of the pointer and don't store it, we must
806 // free it now
807 attr->SafeDecRef();
808 }
809 }
810
811 void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
812 {
813 if ( m_attrProvider )
814 {
815 m_attrProvider->SetColAttr(attr, col);
816 }
817 else
818 {
819 // as we take ownership of the pointer and don't store it, we must
820 // free it now
821 attr->SafeDecRef();
822 }
823 }
824
825 bool wxGridTableBase::InsertRows( size_t pos, size_t numRows )
826 {
827 wxFAIL_MSG( wxT("Called grid table class function InsertRows\n"
828 "but your derived table class does not override this function") );
829
830 return FALSE;
831 }
832
833 bool wxGridTableBase::AppendRows( size_t numRows )
834 {
835 wxFAIL_MSG( wxT("Called grid table class function AppendRows\n"
836 "but your derived table class does not override this function"));
837
838 return FALSE;
839 }
840
841 bool wxGridTableBase::DeleteRows( size_t pos, size_t numRows )
842 {
843 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\n"
844 "but your derived table class does not override this function"));
845
846 return FALSE;
847 }
848
849 bool wxGridTableBase::InsertCols( size_t pos, size_t numCols )
850 {
851 wxFAIL_MSG( wxT("Called grid table class function InsertCols\n"
852 "but your derived table class does not override this function"));
853
854 return FALSE;
855 }
856
857 bool wxGridTableBase::AppendCols( size_t numCols )
858 {
859 wxFAIL_MSG(wxT("Called grid table class function AppendCols\n"
860 "but your derived table class does not override this function"));
861
862 return FALSE;
863 }
864
865 bool wxGridTableBase::DeleteCols( size_t pos, size_t numCols )
866 {
867 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\n"
868 "but your derived table class does not override this function"));
869
870 return FALSE;
871 }
872
873
874 wxString wxGridTableBase::GetRowLabelValue( int row )
875 {
876 wxString s;
877 s << row;
878 return s;
879 }
880
881 wxString wxGridTableBase::GetColLabelValue( int col )
882 {
883 // default col labels are:
884 // cols 0 to 25 : A-Z
885 // cols 26 to 675 : AA-ZZ
886 // etc.
887
888 wxString s;
889 unsigned int i, n;
890 for ( n = 1; ; n++ )
891 {
892 s += (_T('A') + (wxChar)( col%26 ));
893 col = col/26 - 1;
894 if ( col < 0 ) break;
895 }
896
897 // reverse the string...
898 wxString s2;
899 for ( i = 0; i < n; i++ )
900 {
901 s2 += s[n-i-1];
902 }
903
904 return s2;
905 }
906
907
908
909 //////////////////////////////////////////////////////////////////////
910 //
911 // Message class for the grid table to send requests and notifications
912 // to the grid view
913 //
914
915 wxGridTableMessage::wxGridTableMessage()
916 {
917 m_table = (wxGridTableBase *) NULL;
918 m_id = -1;
919 m_comInt1 = -1;
920 m_comInt2 = -1;
921 }
922
923 wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
924 int commandInt1, int commandInt2 )
925 {
926 m_table = table;
927 m_id = id;
928 m_comInt1 = commandInt1;
929 m_comInt2 = commandInt2;
930 }
931
932
933
934 //////////////////////////////////////////////////////////////////////
935 //
936 // A basic grid table for string data. An object of this class will
937 // created by wxGrid if you don't specify an alternative table class.
938 //
939
940 WX_DEFINE_OBJARRAY(wxGridStringArray)
941
942 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
943
944 wxGridStringTable::wxGridStringTable()
945 : wxGridTableBase()
946 {
947 }
948
949 wxGridStringTable::wxGridStringTable( int numRows, int numCols )
950 : wxGridTableBase()
951 {
952 int row, col;
953
954 m_data.Alloc( numRows );
955
956 wxArrayString sa;
957 sa.Alloc( numCols );
958 for ( col = 0; col < numCols; col++ )
959 {
960 sa.Add( wxEmptyString );
961 }
962
963 for ( row = 0; row < numRows; row++ )
964 {
965 m_data.Add( sa );
966 }
967 }
968
969 wxGridStringTable::~wxGridStringTable()
970 {
971 }
972
973 long wxGridStringTable::GetNumberRows()
974 {
975 return m_data.GetCount();
976 }
977
978 long wxGridStringTable::GetNumberCols()
979 {
980 if ( m_data.GetCount() > 0 )
981 return m_data[0].GetCount();
982 else
983 return 0;
984 }
985
986 wxString wxGridStringTable::GetValue( int row, int col )
987 {
988 // TODO: bounds checking
989 //
990 return m_data[row][col];
991 }
992
993 void wxGridStringTable::SetValue( int row, int col, const wxString& s )
994 {
995 // TODO: bounds checking
996 //
997 m_data[row][col] = s;
998 }
999
1000 bool wxGridStringTable::IsEmptyCell( int row, int col )
1001 {
1002 // TODO: bounds checking
1003 //
1004 return (m_data[row][col] == wxEmptyString);
1005 }
1006
1007
1008 void wxGridStringTable::Clear()
1009 {
1010 int row, col;
1011 int numRows, numCols;
1012
1013 numRows = m_data.GetCount();
1014 if ( numRows > 0 )
1015 {
1016 numCols = m_data[0].GetCount();
1017
1018 for ( row = 0; row < numRows; row++ )
1019 {
1020 for ( col = 0; col < numCols; col++ )
1021 {
1022 m_data[row][col] = wxEmptyString;
1023 }
1024 }
1025 }
1026 }
1027
1028
1029 bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
1030 {
1031 size_t row, col;
1032
1033 size_t curNumRows = m_data.GetCount();
1034 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
1035
1036 if ( pos >= curNumRows )
1037 {
1038 return AppendRows( numRows );
1039 }
1040
1041 wxArrayString sa;
1042 sa.Alloc( curNumCols );
1043 for ( col = 0; col < curNumCols; col++ )
1044 {
1045 sa.Add( wxEmptyString );
1046 }
1047
1048 for ( row = pos; row < pos + numRows; row++ )
1049 {
1050 m_data.Insert( sa, row );
1051 }
1052
1053 if ( GetView() )
1054 {
1055 wxGridTableMessage msg( this,
1056 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
1057 pos,
1058 numRows );
1059
1060 GetView()->ProcessTableMessage( msg );
1061 }
1062
1063 return TRUE;
1064 }
1065
1066 bool wxGridStringTable::AppendRows( size_t numRows )
1067 {
1068 size_t row, col;
1069
1070 size_t curNumRows = m_data.GetCount();
1071 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
1072
1073 wxArrayString sa;
1074 if ( curNumCols > 0 )
1075 {
1076 sa.Alloc( curNumCols );
1077 for ( col = 0; col < curNumCols; col++ )
1078 {
1079 sa.Add( wxEmptyString );
1080 }
1081 }
1082
1083 for ( row = 0; row < numRows; row++ )
1084 {
1085 m_data.Add( sa );
1086 }
1087
1088 if ( GetView() )
1089 {
1090 wxGridTableMessage msg( this,
1091 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
1092 numRows );
1093
1094 GetView()->ProcessTableMessage( msg );
1095 }
1096
1097 return TRUE;
1098 }
1099
1100 bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
1101 {
1102 size_t n;
1103
1104 size_t curNumRows = m_data.GetCount();
1105
1106 if ( pos >= curNumRows )
1107 {
1108 wxString errmsg;
1109 errmsg.Printf("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\n"
1110 "Pos value is invalid for present table with %d rows",
1111 pos, numRows, curNumRows );
1112 wxFAIL_MSG( wxT(errmsg) );
1113 return FALSE;
1114 }
1115
1116 if ( numRows > curNumRows - pos )
1117 {
1118 numRows = curNumRows - pos;
1119 }
1120
1121 if ( numRows >= curNumRows )
1122 {
1123 m_data.Empty(); // don't release memory just yet
1124 }
1125 else
1126 {
1127 for ( n = 0; n < numRows; n++ )
1128 {
1129 m_data.Remove( pos );
1130 }
1131 }
1132
1133 if ( GetView() )
1134 {
1135 wxGridTableMessage msg( this,
1136 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
1137 pos,
1138 numRows );
1139
1140 GetView()->ProcessTableMessage( msg );
1141 }
1142
1143 return TRUE;
1144 }
1145
1146 bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
1147 {
1148 size_t row, col;
1149
1150 size_t curNumRows = m_data.GetCount();
1151 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
1152
1153 if ( pos >= curNumCols )
1154 {
1155 return AppendCols( numCols );
1156 }
1157
1158 for ( row = 0; row < curNumRows; row++ )
1159 {
1160 for ( col = pos; col < pos + numCols; col++ )
1161 {
1162 m_data[row].Insert( wxEmptyString, col );
1163 }
1164 }
1165
1166 if ( GetView() )
1167 {
1168 wxGridTableMessage msg( this,
1169 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
1170 pos,
1171 numCols );
1172
1173 GetView()->ProcessTableMessage( msg );
1174 }
1175
1176 return TRUE;
1177 }
1178
1179 bool wxGridStringTable::AppendCols( size_t numCols )
1180 {
1181 size_t row, n;
1182
1183 size_t curNumRows = m_data.GetCount();
1184 if ( !curNumRows )
1185 {
1186 // TODO: something better than this ?
1187 //
1188 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\n"
1189 "Call AppendRows() first") );
1190 return FALSE;
1191 }
1192
1193 for ( row = 0; row < curNumRows; row++ )
1194 {
1195 for ( n = 0; n < numCols; n++ )
1196 {
1197 m_data[row].Add( wxEmptyString );
1198 }
1199 }
1200
1201 if ( GetView() )
1202 {
1203 wxGridTableMessage msg( this,
1204 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
1205 numCols );
1206
1207 GetView()->ProcessTableMessage( msg );
1208 }
1209
1210 return TRUE;
1211 }
1212
1213 bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
1214 {
1215 size_t row, n;
1216
1217 size_t curNumRows = m_data.GetCount();
1218 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
1219
1220 if ( pos >= curNumCols )
1221 {
1222 wxString errmsg;
1223 errmsg.Printf( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
1224 "Pos value is invalid for present table with %d cols",
1225 pos, numCols, curNumCols );
1226 wxFAIL_MSG( wxT( errmsg ) );
1227 return FALSE;
1228 }
1229
1230 if ( numCols > curNumCols - pos )
1231 {
1232 numCols = curNumCols - pos;
1233 }
1234
1235 for ( row = 0; row < curNumRows; row++ )
1236 {
1237 if ( numCols >= curNumCols )
1238 {
1239 m_data[row].Clear();
1240 }
1241 else
1242 {
1243 for ( n = 0; n < numCols; n++ )
1244 {
1245 m_data[row].Remove( pos );
1246 }
1247 }
1248 }
1249
1250 if ( GetView() )
1251 {
1252 wxGridTableMessage msg( this,
1253 wxGRIDTABLE_NOTIFY_COLS_DELETED,
1254 pos,
1255 numCols );
1256
1257 GetView()->ProcessTableMessage( msg );
1258 }
1259
1260 return TRUE;
1261 }
1262
1263 wxString wxGridStringTable::GetRowLabelValue( int row )
1264 {
1265 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
1266 {
1267 // using default label
1268 //
1269 return wxGridTableBase::GetRowLabelValue( row );
1270 }
1271 else
1272 {
1273 return m_rowLabels[ row ];
1274 }
1275 }
1276
1277 wxString wxGridStringTable::GetColLabelValue( int col )
1278 {
1279 if ( col > (int)(m_colLabels.GetCount()) - 1 )
1280 {
1281 // using default label
1282 //
1283 return wxGridTableBase::GetColLabelValue( col );
1284 }
1285 else
1286 {
1287 return m_colLabels[ col ];
1288 }
1289 }
1290
1291 void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
1292 {
1293 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
1294 {
1295 int n = m_rowLabels.GetCount();
1296 int i;
1297 for ( i = n; i <= row; i++ )
1298 {
1299 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
1300 }
1301 }
1302
1303 m_rowLabels[row] = value;
1304 }
1305
1306 void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
1307 {
1308 if ( col > (int)(m_colLabels.GetCount()) - 1 )
1309 {
1310 int n = m_colLabels.GetCount();
1311 int i;
1312 for ( i = n; i <= col; i++ )
1313 {
1314 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
1315 }
1316 }
1317
1318 m_colLabels[col] = value;
1319 }
1320
1321
1322
1323
1324 //////////////////////////////////////////////////////////////////////
1325
1326 IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl, wxTextCtrl )
1327
1328 BEGIN_EVENT_TABLE( wxGridTextCtrl, wxTextCtrl )
1329 EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown )
1330 END_EVENT_TABLE()
1331
1332
1333 wxGridTextCtrl::wxGridTextCtrl( wxWindow *par,
1334 wxGrid *grid,
1335 bool isCellControl,
1336 wxWindowID id,
1337 const wxString& value,
1338 const wxPoint& pos,
1339 const wxSize& size,
1340 long style )
1341 : wxTextCtrl( par, id, value, pos, size, style )
1342 {
1343 m_grid = grid;
1344 m_isCellControl = isCellControl;
1345 }
1346
1347
1348 void wxGridTextCtrl::OnKeyDown( wxKeyEvent& event )
1349 {
1350 switch ( event.KeyCode() )
1351 {
1352 case WXK_ESCAPE:
1353 m_grid->SetEditControlValue( startValue );
1354 SetInsertionPointEnd();
1355 break;
1356
1357 case WXK_UP:
1358 case WXK_DOWN:
1359 case WXK_LEFT:
1360 case WXK_RIGHT:
1361 case WXK_PRIOR:
1362 case WXK_NEXT:
1363 case WXK_SPACE:
1364 if ( m_isCellControl )
1365 {
1366 // send the event to the parent grid, skipping the
1367 // event if nothing happens
1368 //
1369 event.Skip( m_grid->ProcessEvent( event ) );
1370 }
1371 else
1372 {
1373 // default text control response within the top edit
1374 // control
1375 //
1376 event.Skip();
1377 }
1378 break;
1379
1380 case WXK_RETURN:
1381 if ( m_isCellControl )
1382 {
1383 if ( !m_grid->ProcessEvent( event ) )
1384 {
1385 #if defined(__WXMOTIF__) || defined(__WXGTK__)
1386 // wxMotif needs a little extra help...
1387 //
1388 int pos = GetInsertionPoint();
1389 wxString s( GetValue() );
1390 s = s.Left(pos) + "\n" + s.Mid(pos);
1391 SetValue(s);
1392 SetInsertionPoint( pos );
1393 #else
1394 // the other ports can handle a Return key press
1395 //
1396 event.Skip();
1397 #endif
1398 }
1399 }
1400 break;
1401
1402 case WXK_HOME:
1403 case WXK_END:
1404 if ( m_isCellControl )
1405 {
1406 // send the event to the parent grid, skipping the
1407 // event if nothing happens
1408 //
1409 event.Skip( m_grid->ProcessEvent( event ) );
1410 }
1411 else
1412 {
1413 // default text control response within the top edit
1414 // control
1415 //
1416 event.Skip();
1417 }
1418 break;
1419
1420 default:
1421 event.Skip();
1422 }
1423 }
1424
1425 void wxGridTextCtrl::SetStartValue( const wxString& s )
1426 {
1427 startValue = s;
1428 wxTextCtrl::SetValue(s);
1429 }
1430
1431
1432
1433 //////////////////////////////////////////////////////////////////////
1434
1435 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
1436
1437 BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
1438 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
1439 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
1440 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
1441 END_EVENT_TABLE()
1442
1443 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
1444 wxWindowID id,
1445 const wxPoint &pos, const wxSize &size )
1446 : wxWindow( parent, id, pos, size )
1447 {
1448 m_owner = parent;
1449 }
1450
1451 void wxGridRowLabelWindow::OnPaint( wxPaintEvent &event )
1452 {
1453 wxPaintDC dc(this);
1454
1455 // NO - don't do this because it will set both the x and y origin
1456 // coords to match the parent scrolled window and we just want to
1457 // set the y coord - MB
1458 //
1459 // m_owner->PrepareDC( dc );
1460
1461 int x, y;
1462 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
1463 dc.SetDeviceOrigin( 0, -y );
1464
1465 m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
1466 m_owner->DrawRowLabels( dc );
1467 }
1468
1469
1470 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
1471 {
1472 m_owner->ProcessRowLabelMouseEvent( event );
1473 }
1474
1475
1476 // This seems to be required for wxMotif otherwise the mouse
1477 // cursor must be in the cell edit control to get key events
1478 //
1479 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
1480 {
1481 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1482 }
1483
1484
1485
1486 //////////////////////////////////////////////////////////////////////
1487
1488 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
1489
1490 BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
1491 EVT_PAINT( wxGridColLabelWindow::OnPaint )
1492 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
1493 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
1494 END_EVENT_TABLE()
1495
1496 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
1497 wxWindowID id,
1498 const wxPoint &pos, const wxSize &size )
1499 : wxWindow( parent, id, pos, size )
1500 {
1501 m_owner = parent;
1502 }
1503
1504 void wxGridColLabelWindow::OnPaint( wxPaintEvent &event )
1505 {
1506 wxPaintDC dc(this);
1507
1508 // NO - don't do this because it will set both the x and y origin
1509 // coords to match the parent scrolled window and we just want to
1510 // set the x coord - MB
1511 //
1512 // m_owner->PrepareDC( dc );
1513
1514 int x, y;
1515 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
1516 dc.SetDeviceOrigin( -x, 0 );
1517
1518 m_owner->CalcColLabelsExposed( GetUpdateRegion() );
1519 m_owner->DrawColLabels( dc );
1520 }
1521
1522
1523 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
1524 {
1525 m_owner->ProcessColLabelMouseEvent( event );
1526 }
1527
1528
1529 // This seems to be required for wxMotif otherwise the mouse
1530 // cursor must be in the cell edit control to get key events
1531 //
1532 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
1533 {
1534 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1535 }
1536
1537
1538
1539 //////////////////////////////////////////////////////////////////////
1540
1541 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
1542
1543 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
1544 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
1545 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
1546 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
1547 END_EVENT_TABLE()
1548
1549 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
1550 wxWindowID id,
1551 const wxPoint &pos, const wxSize &size )
1552 : wxWindow( parent, id, pos, size )
1553 {
1554 m_owner = parent;
1555 }
1556
1557 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
1558 {
1559 wxPaintDC dc(this);
1560
1561 int client_height = 0;
1562 int client_width = 0;
1563 GetClientSize( &client_width, &client_height );
1564
1565 dc.SetPen( *wxBLACK_PEN );
1566 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
1567 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
1568
1569 dc.SetPen( *wxWHITE_PEN );
1570 dc.DrawLine( 0, 0, client_width, 0 );
1571 dc.DrawLine( 0, 0, 0, client_height );
1572 }
1573
1574
1575 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
1576 {
1577 m_owner->ProcessCornerLabelMouseEvent( event );
1578 }
1579
1580
1581 // This seems to be required for wxMotif otherwise the mouse
1582 // cursor must be in the cell edit control to get key events
1583 //
1584 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
1585 {
1586 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1587 }
1588
1589
1590
1591 //////////////////////////////////////////////////////////////////////
1592
1593 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
1594
1595 BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
1596 EVT_PAINT( wxGridWindow::OnPaint )
1597 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
1598 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
1599 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
1600 END_EVENT_TABLE()
1601
1602 wxGridWindow::wxGridWindow( wxGrid *parent,
1603 wxGridRowLabelWindow *rowLblWin,
1604 wxGridColLabelWindow *colLblWin,
1605 wxWindowID id, const wxPoint &pos, const wxSize &size )
1606 : wxPanel( parent, id, pos, size, 0, "grid window" )
1607 {
1608 m_owner = parent;
1609 m_rowLabelWin = rowLblWin;
1610 m_colLabelWin = colLblWin;
1611 SetBackgroundColour( "WHITE" );
1612 }
1613
1614
1615 wxGridWindow::~wxGridWindow()
1616 {
1617 }
1618
1619
1620 void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1621 {
1622 wxPaintDC dc( this );
1623 m_owner->PrepareDC( dc );
1624 wxRegion reg = GetUpdateRegion();
1625 m_owner->CalcCellsExposed( reg );
1626 m_owner->DrawGridCellArea( dc );
1627 #if WXGRID_DRAW_LINES
1628 m_owner->DrawAllGridLines( dc, reg );
1629 #endif
1630 }
1631
1632
1633 void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1634 {
1635 wxPanel::ScrollWindow( dx, dy, rect );
1636 m_rowLabelWin->ScrollWindow( 0, dy, rect );
1637 m_colLabelWin->ScrollWindow( dx, 0, rect );
1638 }
1639
1640
1641 void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
1642 {
1643 m_owner->ProcessGridCellMouseEvent( event );
1644 }
1645
1646
1647 // This seems to be required for wxMotif otherwise the mouse
1648 // cursor must be in the cell edit control to get key events
1649 //
1650 void wxGridWindow::OnKeyDown( wxKeyEvent& event )
1651 {
1652 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1653 }
1654
1655 void wxGridWindow::OnEraseBackground(wxEraseEvent&)
1656 { }
1657
1658
1659
1660 //////////////////////////////////////////////////////////////////////
1661
1662 IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
1663
1664 BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
1665 EVT_PAINT( wxGrid::OnPaint )
1666 EVT_SIZE( wxGrid::OnSize )
1667 EVT_KEY_DOWN( wxGrid::OnKeyDown )
1668 EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground )
1669 END_EVENT_TABLE()
1670
1671 wxGrid::wxGrid( wxWindow *parent,
1672 wxWindowID id,
1673 const wxPoint& pos,
1674 const wxSize& size,
1675 long style,
1676 const wxString& name )
1677 : wxScrolledWindow( parent, id, pos, size, style, name )
1678 {
1679 Create();
1680 }
1681
1682
1683 wxGrid::~wxGrid()
1684 {
1685 ClearAttrCache();
1686 m_defaultCellAttr->SafeDecRef();
1687
1688 #ifdef DEBUG_ATTR_CACHE
1689 size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
1690 wxPrintf(_T("wxGrid attribute cache statistics: "
1691 "total: %u, hits: %u (%u%%)\n"),
1692 total, gs_nAttrCacheHits,
1693 total ? (gs_nAttrCacheHits*100) / total : 0);
1694 #endif
1695
1696 if (m_ownTable)
1697 delete m_table;
1698 }
1699
1700
1701 //
1702 // ----- internal init and update functions
1703 //
1704
1705 void wxGrid::Create()
1706 {
1707 m_created = FALSE; // set to TRUE by CreateGrid
1708 m_displayed = FALSE; // set to TRUE by OnPaint
1709
1710 m_table = (wxGridTableBase *) NULL;
1711 m_ownTable = FALSE;
1712 m_cellEditCtrl = (wxWindow *) NULL;
1713
1714 m_defaultCellAttr = new wxGridCellAttr;
1715 m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
1716 // RD: Should we fill the default attrs now or is waiting until Init() okay?
1717
1718
1719 m_numRows = 0;
1720 m_numCols = 0;
1721 m_currentCellCoords = wxGridNoCellCoords;
1722
1723 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
1724 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
1725
1726 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
1727 -1,
1728 wxDefaultPosition,
1729 wxDefaultSize );
1730
1731 m_rowLabelWin = new wxGridRowLabelWindow( this,
1732 -1,
1733 wxDefaultPosition,
1734 wxDefaultSize );
1735
1736 m_colLabelWin = new wxGridColLabelWindow( this,
1737 -1,
1738 wxDefaultPosition,
1739 wxDefaultSize );
1740
1741 m_gridWin = new wxGridWindow( this,
1742 m_rowLabelWin,
1743 m_colLabelWin,
1744 -1,
1745 wxDefaultPosition,
1746 wxDefaultSize );
1747
1748 SetTargetWindow( m_gridWin );
1749 }
1750
1751
1752 bool wxGrid::CreateGrid( int numRows, int numCols )
1753 {
1754 if ( m_created )
1755 {
1756 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
1757 return FALSE;
1758 }
1759 else
1760 {
1761 m_numRows = numRows;
1762 m_numCols = numCols;
1763
1764 m_table = new wxGridStringTable( m_numRows, m_numCols );
1765 m_table->SetView( this );
1766 m_ownTable = TRUE;
1767 Init();
1768 m_created = TRUE;
1769 }
1770
1771 return m_created;
1772 }
1773
1774 bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership )
1775 {
1776 if ( m_created )
1777 {
1778 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
1779 return FALSE;
1780 }
1781 else
1782 {
1783 m_numRows = table->GetNumberRows();
1784 m_numCols = table->GetNumberCols();
1785
1786 m_table = table;
1787 m_table->SetView( this );
1788 if (takeOwnership)
1789 m_ownTable = TRUE;
1790 Init();
1791 m_created = TRUE;
1792 }
1793
1794 return m_created;
1795 }
1796
1797
1798 void wxGrid::Init()
1799 {
1800 int i;
1801
1802 if ( m_numRows <= 0 )
1803 m_numRows = WXGRID_DEFAULT_NUMBER_ROWS;
1804
1805 if ( m_numCols <= 0 )
1806 m_numCols = WXGRID_DEFAULT_NUMBER_COLS;
1807
1808 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
1809 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
1810
1811 if ( m_rowLabelWin )
1812 {
1813 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
1814 }
1815 else
1816 {
1817 m_labelBackgroundColour = wxColour( _T("WHITE") );
1818 }
1819
1820 m_labelTextColour = wxColour( _T("BLACK") );
1821
1822 // init attr cache
1823 m_attrCache.row = -1;
1824
1825 // TODO: something better than this ?
1826 //
1827 m_labelFont = this->GetFont();
1828 m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 );
1829
1830 m_rowLabelHorizAlign = wxLEFT;
1831 m_rowLabelVertAlign = wxCENTRE;
1832
1833 m_colLabelHorizAlign = wxCENTRE;
1834 m_colLabelVertAlign = wxTOP;
1835
1836 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
1837 m_defaultRowHeight = m_gridWin->GetCharHeight();
1838
1839 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
1840 m_defaultRowHeight += 8;
1841 #else
1842 m_defaultRowHeight += 4;
1843 #endif
1844
1845 m_rowHeights.Alloc( m_numRows );
1846 m_rowBottoms.Alloc( m_numRows );
1847 int rowBottom = 0;
1848 for ( i = 0; i < m_numRows; i++ )
1849 {
1850 m_rowHeights.Add( m_defaultRowHeight );
1851 rowBottom += m_defaultRowHeight;
1852 m_rowBottoms.Add( rowBottom );
1853 }
1854
1855 m_colWidths.Alloc( m_numCols );
1856 m_colRights.Alloc( m_numCols );
1857 int colRight = 0;
1858 for ( i = 0; i < m_numCols; i++ )
1859 {
1860 m_colWidths.Add( m_defaultColWidth );
1861 colRight += m_defaultColWidth;
1862 m_colRights.Add( colRight );
1863 }
1864
1865 m_defaultCellAttr->SetFont(GetFont());
1866 m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP);
1867 m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
1868 m_defaultCellAttr->SetTextColour(
1869 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
1870 m_defaultCellAttr->SetBackgroundColour(
1871 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
1872
1873
1874 m_gridLineColour = wxColour( 128, 128, 255 );
1875 m_gridLinesEnabled = TRUE;
1876
1877 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1878 m_winCapture = (wxWindow *)NULL;
1879 m_dragLastPos = -1;
1880 m_dragRowOrCol = -1;
1881 m_isDragging = FALSE;
1882
1883 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
1884 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
1885
1886 m_currentCellCoords = wxGridNoCellCoords;
1887
1888 m_selectedTopLeft = wxGridNoCellCoords;
1889 m_selectedBottomRight = wxGridNoCellCoords;
1890 m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT);
1891 m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
1892
1893 m_editable = TRUE; // default for whole grid
1894
1895 m_inOnKeyDown = FALSE;
1896 m_batchCount = 0;
1897
1898 // TODO: extend this to other types of controls
1899 //
1900 m_cellEditCtrl = new wxGridTextCtrl( m_gridWin,
1901 this,
1902 FALSE,
1903 wxGRID_CELLCTRL,
1904 "",
1905 wxPoint(1,1),
1906 wxSize(1,1)
1907 #if defined(__WXMSW__)
1908 , wxTE_MULTILINE | wxTE_NO_VSCROLL
1909 #endif
1910 );
1911
1912 m_cellEditCtrl->Show( FALSE );
1913 m_cellEditCtrlEnabled = FALSE;
1914 m_editCtrlType = wxGRID_TEXTCTRL;
1915 }
1916
1917
1918 void wxGrid::CalcDimensions()
1919 {
1920 int cw, ch;
1921 GetClientSize( &cw, &ch );
1922
1923 if ( m_numRows > 0 && m_numCols > 0 )
1924 {
1925 int right = m_colRights[ m_numCols-1 ] + 50;
1926 int bottom = m_rowBottoms[ m_numRows-1 ] + 50;
1927
1928 // TODO: restore the scroll position that we had before sizing
1929 //
1930 int x, y;
1931 GetViewStart( &x, &y );
1932 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
1933 right/GRID_SCROLL_LINE, bottom/GRID_SCROLL_LINE,
1934 x, y );
1935 }
1936 }
1937
1938
1939 void wxGrid::CalcWindowSizes()
1940 {
1941 int cw, ch;
1942 GetClientSize( &cw, &ch );
1943
1944 if ( m_cornerLabelWin->IsShown() )
1945 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
1946
1947 if ( m_colLabelWin->IsShown() )
1948 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
1949
1950 if ( m_rowLabelWin->IsShown() )
1951 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
1952
1953 if ( m_gridWin->IsShown() )
1954 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
1955 }
1956
1957
1958 // this is called when the grid table sends a message to say that it
1959 // has been redimensioned
1960 //
1961 bool wxGrid::Redimension( wxGridTableMessage& msg )
1962 {
1963 int i;
1964
1965 switch ( msg.GetId() )
1966 {
1967 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
1968 {
1969 size_t pos = msg.GetCommandInt();
1970 int numRows = msg.GetCommandInt2();
1971 for ( i = 0; i < numRows; i++ )
1972 {
1973 m_rowHeights.Insert( m_defaultRowHeight, pos );
1974 m_rowBottoms.Insert( 0, pos );
1975 }
1976 m_numRows += numRows;
1977
1978 int bottom = 0;
1979 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
1980
1981 for ( i = pos; i < m_numRows; i++ )
1982 {
1983 bottom += m_rowHeights[i];
1984 m_rowBottoms[i] = bottom;
1985 }
1986 CalcDimensions();
1987 }
1988 return TRUE;
1989
1990 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
1991 {
1992 int numRows = msg.GetCommandInt();
1993 for ( i = 0; i < numRows; i++ )
1994 {
1995 m_rowHeights.Add( m_defaultRowHeight );
1996 m_rowBottoms.Add( 0 );
1997 }
1998
1999 int oldNumRows = m_numRows;
2000 m_numRows += numRows;
2001
2002 int bottom = 0;
2003 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
2004
2005 for ( i = oldNumRows; i < m_numRows; i++ )
2006 {
2007 bottom += m_rowHeights[i];
2008 m_rowBottoms[i] = bottom;
2009 }
2010 CalcDimensions();
2011 }
2012 return TRUE;
2013
2014 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
2015 {
2016 size_t pos = msg.GetCommandInt();
2017 int numRows = msg.GetCommandInt2();
2018 for ( i = 0; i < numRows; i++ )
2019 {
2020 m_rowHeights.Remove( pos );
2021 m_rowBottoms.Remove( pos );
2022 }
2023 m_numRows -= numRows;
2024
2025 if ( !m_numRows )
2026 {
2027 m_numCols = 0;
2028 m_colWidths.Clear();
2029 m_colRights.Clear();
2030 m_currentCellCoords = wxGridNoCellCoords;
2031 }
2032 else
2033 {
2034 if ( m_currentCellCoords.GetRow() >= m_numRows )
2035 m_currentCellCoords.Set( 0, 0 );
2036
2037 int h = 0;
2038 for ( i = 0; i < m_numRows; i++ )
2039 {
2040 h += m_rowHeights[i];
2041 m_rowBottoms[i] = h;
2042 }
2043 }
2044
2045 CalcDimensions();
2046 }
2047 return TRUE;
2048
2049 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
2050 {
2051 size_t pos = msg.GetCommandInt();
2052 int numCols = msg.GetCommandInt2();
2053 for ( i = 0; i < numCols; i++ )
2054 {
2055 m_colWidths.Insert( m_defaultColWidth, pos );
2056 m_colRights.Insert( 0, pos );
2057 }
2058 m_numCols += numCols;
2059
2060 int right = 0;
2061 if ( pos > 0 ) right = m_colRights[pos-1];
2062
2063 for ( i = pos; i < m_numCols; i++ )
2064 {
2065 right += m_colWidths[i];
2066 m_colRights[i] = right;
2067 }
2068 CalcDimensions();
2069 }
2070 return TRUE;
2071
2072 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
2073 {
2074 int numCols = msg.GetCommandInt();
2075 for ( i = 0; i < numCols; i++ )
2076 {
2077 m_colWidths.Add( m_defaultColWidth );
2078 m_colRights.Add( 0 );
2079 }
2080
2081 int oldNumCols = m_numCols;
2082 m_numCols += numCols;
2083
2084 int right = 0;
2085 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
2086
2087 for ( i = oldNumCols; i < m_numCols; i++ )
2088 {
2089 right += m_colWidths[i];
2090 m_colRights[i] = right;
2091 }
2092 CalcDimensions();
2093 }
2094 return TRUE;
2095
2096 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
2097 {
2098 size_t pos = msg.GetCommandInt();
2099 int numCols = msg.GetCommandInt2();
2100 for ( i = 0; i < numCols; i++ )
2101 {
2102 m_colWidths.Remove( pos );
2103 m_colRights.Remove( pos );
2104 }
2105 m_numCols -= numCols;
2106
2107 if ( !m_numCols )
2108 {
2109 #if 0 // leave the row alone here so that AppendCols will work subsequently
2110 m_numRows = 0;
2111 m_rowHeights.Clear();
2112 m_rowBottoms.Clear();
2113 #endif
2114 m_currentCellCoords = wxGridNoCellCoords;
2115 }
2116 else
2117 {
2118 if ( m_currentCellCoords.GetCol() >= m_numCols )
2119 m_currentCellCoords.Set( 0, 0 );
2120
2121 int w = 0;
2122 for ( i = 0; i < m_numCols; i++ )
2123 {
2124 w += m_colWidths[i];
2125 m_colRights[i] = w;
2126 }
2127 }
2128 CalcDimensions();
2129 }
2130 return TRUE;
2131 }
2132
2133 return FALSE;
2134 }
2135
2136
2137 void wxGrid::CalcRowLabelsExposed( wxRegion& reg )
2138 {
2139 wxRegionIterator iter( reg );
2140 wxRect r;
2141
2142 m_rowLabelsExposed.Empty();
2143
2144 int top, bottom;
2145 while ( iter )
2146 {
2147 r = iter.GetRect();
2148
2149 // TODO: remove this when we can...
2150 // There is a bug in wxMotif that gives garbage update
2151 // rectangles if you jump-scroll a long way by clicking the
2152 // scrollbar with middle button. This is a work-around
2153 //
2154 #if defined(__WXMOTIF__)
2155 int cw, ch;
2156 m_gridWin->GetClientSize( &cw, &ch );
2157 if ( r.GetTop() > ch ) r.SetTop( 0 );
2158 r.SetBottom( wxMin( r.GetBottom(), ch ) );
2159 #endif
2160
2161 // logical bounds of update region
2162 //
2163 int dummy;
2164 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
2165 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
2166
2167 // find the row labels within these bounds
2168 //
2169 int row;
2170 int rowTop;
2171 for ( row = 0; row < m_numRows; row++ )
2172 {
2173 if ( m_rowBottoms[row] < top ) continue;
2174
2175 rowTop = m_rowBottoms[row] - m_rowHeights[row];
2176 if ( rowTop > bottom ) break;
2177
2178 m_rowLabelsExposed.Add( row );
2179 }
2180
2181 iter++ ;
2182 }
2183 }
2184
2185
2186 void wxGrid::CalcColLabelsExposed( wxRegion& reg )
2187 {
2188 wxRegionIterator iter( reg );
2189 wxRect r;
2190
2191 m_colLabelsExposed.Empty();
2192
2193 int left, right;
2194 while ( iter )
2195 {
2196 r = iter.GetRect();
2197
2198 // TODO: remove this when we can...
2199 // There is a bug in wxMotif that gives garbage update
2200 // rectangles if you jump-scroll a long way by clicking the
2201 // scrollbar with middle button. This is a work-around
2202 //
2203 #if defined(__WXMOTIF__)
2204 int cw, ch;
2205 m_gridWin->GetClientSize( &cw, &ch );
2206 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
2207 r.SetRight( wxMin( r.GetRight(), cw ) );
2208 #endif
2209
2210 // logical bounds of update region
2211 //
2212 int dummy;
2213 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
2214 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
2215
2216 // find the cells within these bounds
2217 //
2218 int col;
2219 int colLeft;
2220 for ( col = 0; col < m_numCols; col++ )
2221 {
2222 if ( m_colRights[col] < left ) continue;
2223
2224 colLeft = m_colRights[col] - m_colWidths[col];
2225 if ( colLeft > right ) break;
2226
2227 m_colLabelsExposed.Add( col );
2228 }
2229
2230 iter++ ;
2231 }
2232 }
2233
2234
2235 void wxGrid::CalcCellsExposed( wxRegion& reg )
2236 {
2237 wxRegionIterator iter( reg );
2238 wxRect r;
2239
2240 m_cellsExposed.Empty();
2241 m_rowsExposed.Empty();
2242 m_colsExposed.Empty();
2243
2244 int left, top, right, bottom;
2245 while ( iter )
2246 {
2247 r = iter.GetRect();
2248
2249 // TODO: remove this when we can...
2250 // There is a bug in wxMotif that gives garbage update
2251 // rectangles if you jump-scroll a long way by clicking the
2252 // scrollbar with middle button. This is a work-around
2253 //
2254 #if defined(__WXMOTIF__)
2255 int cw, ch;
2256 m_gridWin->GetClientSize( &cw, &ch );
2257 if ( r.GetTop() > ch ) r.SetTop( 0 );
2258 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
2259 r.SetRight( wxMin( r.GetRight(), cw ) );
2260 r.SetBottom( wxMin( r.GetBottom(), ch ) );
2261 #endif
2262
2263 // logical bounds of update region
2264 //
2265 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
2266 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
2267
2268 // find the cells within these bounds
2269 //
2270 int row, col;
2271 int colLeft, rowTop;
2272 for ( row = 0; row < m_numRows; row++ )
2273 {
2274 if ( m_rowBottoms[row] < top ) continue;
2275
2276 rowTop = m_rowBottoms[row] - m_rowHeights[row];
2277 if ( rowTop > bottom ) break;
2278
2279 m_rowsExposed.Add( row );
2280
2281 for ( col = 0; col < m_numCols; col++ )
2282 {
2283 if ( m_colRights[col] < left ) continue;
2284
2285 colLeft = m_colRights[col] - m_colWidths[col];
2286 if ( colLeft > right ) break;
2287
2288 if ( m_colsExposed.Index( col ) == wxNOT_FOUND ) m_colsExposed.Add( col );
2289 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
2290 }
2291 }
2292
2293 iter++ ;
2294 }
2295 }
2296
2297
2298 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
2299 {
2300 int x, y, row;
2301 wxPoint pos( event.GetPosition() );
2302 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
2303
2304 if ( event.Dragging() )
2305 {
2306 m_isDragging = TRUE;
2307
2308 if ( event.LeftIsDown() )
2309 {
2310 switch( m_cursorMode )
2311 {
2312 case WXGRID_CURSOR_RESIZE_ROW:
2313 {
2314 int cw, ch, left, dummy;
2315 m_gridWin->GetClientSize( &cw, &ch );
2316 CalcUnscrolledPosition( 0, 0, &left, &dummy );
2317
2318 wxClientDC dc( m_gridWin );
2319 PrepareDC( dc );
2320 dc.SetLogicalFunction(wxINVERT);
2321 if ( m_dragLastPos >= 0 )
2322 {
2323 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
2324 }
2325 dc.DrawLine( left, y, left+cw, y );
2326 m_dragLastPos = y;
2327 }
2328 break;
2329
2330 case WXGRID_CURSOR_SELECT_ROW:
2331 if ( (row = YToRow( y )) >= 0 &&
2332 !IsInSelection( row, 0 ) )
2333 {
2334 SelectRow( row, TRUE );
2335 }
2336
2337 // default label to suppress warnings about "enumeration value
2338 // 'xxx' not handled in switch
2339 default:
2340 break;
2341 }
2342 }
2343 return;
2344 }
2345
2346 m_isDragging = FALSE;
2347
2348
2349 // ------------ Entering or leaving the window
2350 //
2351 if ( event.Entering() || event.Leaving() )
2352 {
2353 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
2354 }
2355
2356
2357 // ------------ Left button pressed
2358 //
2359 else if ( event.LeftDown() )
2360 {
2361 // don't send a label click event for a hit on the
2362 // edge of the row label - this is probably the user
2363 // wanting to resize the row
2364 //
2365 if ( YToEdgeOfRow(y) < 0 )
2366 {
2367 row = YToRow(y);
2368 if ( row >= 0 &&
2369 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
2370 {
2371 SelectRow( row, event.ShiftDown() );
2372 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
2373 }
2374 }
2375 else
2376 {
2377 // starting to drag-resize a row
2378 //
2379 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
2380 }
2381 }
2382
2383
2384 // ------------ Left double click
2385 //
2386 else if (event.LeftDClick() )
2387 {
2388 if ( YToEdgeOfRow(y) < 0 )
2389 {
2390 row = YToRow(y);
2391 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
2392 }
2393 }
2394
2395
2396 // ------------ Left button released
2397 //
2398 else if ( event.LeftUp() )
2399 {
2400 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2401 {
2402 DoEndDragResizeRow();
2403
2404 // Note: we are ending the event *after* doing
2405 // default processing in this case
2406 //
2407 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
2408 }
2409
2410 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
2411 m_dragLastPos = -1;
2412 }
2413
2414
2415 // ------------ Right button down
2416 //
2417 else if ( event.RightDown() )
2418 {
2419 row = YToRow(y);
2420 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
2421 {
2422 // no default action at the moment
2423 }
2424 }
2425
2426
2427 // ------------ Right double click
2428 //
2429 else if ( event.RightDClick() )
2430 {
2431 row = YToRow(y);
2432 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
2433 {
2434 // no default action at the moment
2435 }
2436 }
2437
2438
2439 // ------------ No buttons down and mouse moving
2440 //
2441 else if ( event.Moving() )
2442 {
2443 m_dragRowOrCol = YToEdgeOfRow( y );
2444 if ( m_dragRowOrCol >= 0 )
2445 {
2446 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2447 {
2448 // don't capture the mouse yet
2449 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
2450 }
2451 }
2452 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2453 {
2454 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
2455 }
2456 }
2457 }
2458
2459
2460 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
2461 {
2462 int x, y, col;
2463 wxPoint pos( event.GetPosition() );
2464 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
2465
2466 if ( event.Dragging() )
2467 {
2468 m_isDragging = TRUE;
2469
2470 if ( event.LeftIsDown() )
2471 {
2472 switch( m_cursorMode )
2473 {
2474 case WXGRID_CURSOR_RESIZE_COL:
2475 {
2476 int cw, ch, dummy, top;
2477 m_gridWin->GetClientSize( &cw, &ch );
2478 CalcUnscrolledPosition( 0, 0, &dummy, &top );
2479
2480 wxClientDC dc( m_gridWin );
2481 PrepareDC( dc );
2482 dc.SetLogicalFunction(wxINVERT);
2483 if ( m_dragLastPos >= 0 )
2484 {
2485 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
2486 }
2487 dc.DrawLine( x, top, x, top+ch );
2488 m_dragLastPos = x;
2489 }
2490 break;
2491
2492 case WXGRID_CURSOR_SELECT_COL:
2493 if ( (col = XToCol( x )) >= 0 &&
2494 !IsInSelection( 0, col ) )
2495 {
2496 SelectCol( col, TRUE );
2497 }
2498
2499 // default label to suppress warnings about "enumeration value
2500 // 'xxx' not handled in switch
2501 default:
2502 break;
2503 }
2504 }
2505 return;
2506 }
2507
2508 m_isDragging = FALSE;
2509
2510
2511 // ------------ Entering or leaving the window
2512 //
2513 if ( event.Entering() || event.Leaving() )
2514 {
2515 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
2516 }
2517
2518
2519 // ------------ Left button pressed
2520 //
2521 else if ( event.LeftDown() )
2522 {
2523 // don't send a label click event for a hit on the
2524 // edge of the col label - this is probably the user
2525 // wanting to resize the col
2526 //
2527 if ( XToEdgeOfCol(x) < 0 )
2528 {
2529 col = XToCol(x);
2530 if ( col >= 0 &&
2531 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
2532 {
2533 SelectCol( col, event.ShiftDown() );
2534 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
2535 }
2536 }
2537 else
2538 {
2539 // starting to drag-resize a col
2540 //
2541 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
2542 }
2543 }
2544
2545
2546 // ------------ Left double click
2547 //
2548 if ( event.LeftDClick() )
2549 {
2550 if ( XToEdgeOfCol(x) < 0 )
2551 {
2552 col = XToCol(x);
2553 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
2554 }
2555 }
2556
2557
2558 // ------------ Left button released
2559 //
2560 else if ( event.LeftUp() )
2561 {
2562 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2563 {
2564 DoEndDragResizeCol();
2565
2566 // Note: we are ending the event *after* doing
2567 // default processing in this case
2568 //
2569 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2570 }
2571
2572 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
2573 m_dragLastPos = -1;
2574 }
2575
2576
2577 // ------------ Right button down
2578 //
2579 else if ( event.RightDown() )
2580 {
2581 col = XToCol(x);
2582 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
2583 {
2584 // no default action at the moment
2585 }
2586 }
2587
2588
2589 // ------------ Right double click
2590 //
2591 else if ( event.RightDClick() )
2592 {
2593 col = XToCol(x);
2594 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
2595 {
2596 // no default action at the moment
2597 }
2598 }
2599
2600
2601 // ------------ No buttons down and mouse moving
2602 //
2603 else if ( event.Moving() )
2604 {
2605 m_dragRowOrCol = XToEdgeOfCol( x );
2606 if ( m_dragRowOrCol >= 0 )
2607 {
2608 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2609 {
2610 // don't capture the cursor yet
2611 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
2612 }
2613 }
2614 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2615 {
2616 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
2617 }
2618 }
2619 }
2620
2621
2622 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
2623 {
2624 if ( event.LeftDown() )
2625 {
2626 // indicate corner label by having both row and
2627 // col args == -1
2628 //
2629 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
2630 {
2631 SelectAll();
2632 }
2633 }
2634
2635 else if ( event.LeftDClick() )
2636 {
2637 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
2638 }
2639
2640 else if ( event.RightDown() )
2641 {
2642 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
2643 {
2644 // no default action at the moment
2645 }
2646 }
2647
2648 else if ( event.RightDClick() )
2649 {
2650 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
2651 {
2652 // no default action at the moment
2653 }
2654 }
2655 }
2656
2657 void wxGrid::ChangeCursorMode(CursorMode mode,
2658 wxWindow *win,
2659 bool captureMouse)
2660 {
2661 #ifdef __WXDEBUG__
2662 static const wxChar *cursorModes[] =
2663 {
2664 _T("SELECT_CELL"),
2665 _T("RESIZE_ROW"),
2666 _T("RESIZE_COL"),
2667 _T("SELECT_ROW"),
2668 _T("SELECT_COL")
2669 };
2670
2671 wxLogTrace(_T("grid"),
2672 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
2673 win == m_colLabelWin ? _T("colLabelWin")
2674 : win ? _T("rowLabelWin")
2675 : _T("gridWin"),
2676 cursorModes[m_cursorMode], cursorModes[mode]);
2677 #endif // __WXDEBUG__
2678
2679 if ( mode == m_cursorMode )
2680 return;
2681
2682 if ( !win )
2683 {
2684 // by default use the grid itself
2685 win = m_gridWin;
2686 }
2687
2688 if ( m_winCapture )
2689 {
2690 m_winCapture->ReleaseMouse();
2691 m_winCapture = (wxWindow *)NULL;
2692 }
2693
2694 m_cursorMode = mode;
2695
2696 switch ( m_cursorMode )
2697 {
2698 case WXGRID_CURSOR_RESIZE_ROW:
2699 win->SetCursor( m_rowResizeCursor );
2700 break;
2701
2702 case WXGRID_CURSOR_RESIZE_COL:
2703 win->SetCursor( m_colResizeCursor );
2704 break;
2705
2706 default:
2707 win->SetCursor( *wxSTANDARD_CURSOR );
2708 }
2709
2710 // we need to capture mouse when resizing
2711 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
2712 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
2713
2714 if ( captureMouse && resize )
2715 {
2716 win->CaptureMouse();
2717 m_winCapture = win;
2718 }
2719 }
2720
2721 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
2722 {
2723 int x, y;
2724 wxPoint pos( event.GetPosition() );
2725 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
2726
2727 wxGridCellCoords coords;
2728 XYToCell( x, y, coords );
2729
2730 if ( event.Dragging() )
2731 {
2732 m_isDragging = TRUE;
2733 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2734 {
2735 // Hide the edit control, so it
2736 // won't interfer with drag-shrinking.
2737 if ( IsCellEditControlEnabled() )
2738 HideCellEditControl();
2739 if ( coords != wxGridNoCellCoords )
2740 {
2741 if ( !IsSelection() )
2742 {
2743 SelectBlock( coords, coords );
2744 }
2745 else
2746 {
2747 SelectBlock( m_currentCellCoords, coords );
2748 }
2749 }
2750 }
2751 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2752 {
2753 int cw, ch, left, dummy;
2754 m_gridWin->GetClientSize( &cw, &ch );
2755 CalcUnscrolledPosition( 0, 0, &left, &dummy );
2756
2757 wxClientDC dc( m_gridWin );
2758 PrepareDC( dc );
2759 dc.SetLogicalFunction(wxINVERT);
2760 if ( m_dragLastPos >= 0 )
2761 {
2762 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
2763 }
2764 dc.DrawLine( left, y, left+cw, y );
2765 m_dragLastPos = y;
2766 }
2767 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2768 {
2769 int cw, ch, dummy, top;
2770 m_gridWin->GetClientSize( &cw, &ch );
2771 CalcUnscrolledPosition( 0, 0, &dummy, &top );
2772
2773 wxClientDC dc( m_gridWin );
2774 PrepareDC( dc );
2775 dc.SetLogicalFunction(wxINVERT);
2776 if ( m_dragLastPos >= 0 )
2777 {
2778 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
2779 }
2780 dc.DrawLine( x, top, x, top+ch );
2781 m_dragLastPos = x;
2782 }
2783
2784 return;
2785 }
2786
2787 m_isDragging = FALSE;
2788
2789 if ( coords != wxGridNoCellCoords )
2790 {
2791 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
2792 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
2793 // wxGTK
2794 #if 0
2795 if ( event.Entering() || event.Leaving() )
2796 {
2797 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2798 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
2799 }
2800 else
2801 #endif // 0
2802
2803 // ------------ Left button pressed
2804 //
2805 if ( event.LeftDown() )
2806 {
2807 if ( event.AltDown() )
2808 {
2809 MakeCellVisible( coords );
2810 SetCurrentCell( coords );
2811 EnableCellEditControl( TRUE );
2812 }
2813 else
2814 {
2815 EnableCellEditControl( FALSE );
2816 }
2817 if ( event.ShiftDown() )
2818 {
2819 SelectBlock( m_currentCellCoords, coords );
2820 }
2821 else if ( XToEdgeOfCol(x) < 0 &&
2822 YToEdgeOfRow(y) < 0 )
2823 {
2824 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK,
2825 coords.GetRow(),
2826 coords.GetCol(),
2827 event ) )
2828 {
2829 MakeCellVisible( coords );
2830 SetCurrentCell( coords );
2831 }
2832 }
2833 }
2834
2835
2836 // ------------ Left double click
2837 //
2838 else if ( event.LeftDClick() )
2839 {
2840 EnableCellEditControl( FALSE );
2841 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
2842 {
2843 SendEvent( EVT_GRID_CELL_LEFT_DCLICK,
2844 coords.GetRow(),
2845 coords.GetCol(),
2846 event );
2847 }
2848 }
2849
2850
2851 // ------------ Left button released
2852 //
2853 else if ( event.LeftUp() )
2854 {
2855 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2856 {
2857 if ( IsSelection() )
2858 {
2859 SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, event );
2860 }
2861
2862 // Show the edit control, if it has
2863 // been hidden for drag-shrinking.
2864 if ( IsCellEditControlEnabled() )
2865 ShowCellEditControl();
2866 }
2867 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2868 {
2869 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2870 DoEndDragResizeRow();
2871
2872 // Note: we are ending the event *after* doing
2873 // default processing in this case
2874 //
2875 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
2876 }
2877 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2878 {
2879 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2880 DoEndDragResizeCol();
2881
2882 // Note: we are ending the event *after* doing
2883 // default processing in this case
2884 //
2885 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2886 }
2887
2888 m_dragLastPos = -1;
2889 }
2890
2891
2892 // ------------ Right button down
2893 //
2894 else if ( event.RightDown() )
2895 {
2896 EnableCellEditControl( FALSE );
2897 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK,
2898 coords.GetRow(),
2899 coords.GetCol(),
2900 event ) )
2901 {
2902 // no default action at the moment
2903 }
2904 }
2905
2906
2907 // ------------ Right double click
2908 //
2909 else if ( event.RightDClick() )
2910 {
2911 EnableCellEditControl( FALSE );
2912 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK,
2913 coords.GetRow(),
2914 coords.GetCol(),
2915 event ) )
2916 {
2917 // no default action at the moment
2918 }
2919 }
2920
2921 // ------------ Moving and no button action
2922 //
2923 else if ( event.Moving() && !event.IsButton() )
2924 {
2925 int dragRow = YToEdgeOfRow( y );
2926 int dragCol = XToEdgeOfCol( x );
2927
2928 // Dragging on the corner of a cell to resize in both
2929 // directions is not implemented yet...
2930 //
2931 if ( dragRow >= 0 && dragCol >= 0 )
2932 {
2933 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2934 return;
2935 }
2936
2937 if ( dragRow >= 0 )
2938 {
2939 m_dragRowOrCol = dragRow;
2940
2941 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2942 {
2943 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
2944 }
2945
2946 return;
2947 }
2948
2949 if ( dragCol >= 0 )
2950 {
2951 m_dragRowOrCol = dragCol;
2952
2953 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2954 {
2955 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
2956 }
2957
2958 return;
2959 }
2960
2961 // Neither on a row or col edge
2962 //
2963 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2964 {
2965 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2966 }
2967 }
2968 }
2969 }
2970
2971
2972 void wxGrid::DoEndDragResizeRow()
2973 {
2974 if ( m_dragLastPos >= 0 )
2975 {
2976 // erase the last line and resize the row
2977 //
2978 int cw, ch, left, dummy;
2979 m_gridWin->GetClientSize( &cw, &ch );
2980 CalcUnscrolledPosition( 0, 0, &left, &dummy );
2981
2982 wxClientDC dc( m_gridWin );
2983 PrepareDC( dc );
2984 dc.SetLogicalFunction( wxINVERT );
2985 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
2986 HideCellEditControl();
2987
2988 int rowTop = m_rowBottoms[m_dragRowOrCol] - m_rowHeights[m_dragRowOrCol];
2989 SetRowSize( m_dragRowOrCol,
2990 wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
2991
2992 if ( !GetBatchCount() )
2993 {
2994 // Only needed to get the correct rect.y:
2995 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
2996 rect.x = 0;
2997 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
2998 rect.width = m_rowLabelWidth;
2999 rect.height = ch - rect.y;
3000 m_rowLabelWin->Refresh( TRUE, &rect );
3001 rect.width = cw;
3002 m_gridWin->Refresh( FALSE, &rect );
3003 }
3004
3005 ShowCellEditControl();
3006 }
3007 }
3008
3009
3010 void wxGrid::DoEndDragResizeCol()
3011 {
3012 if ( m_dragLastPos >= 0 )
3013 {
3014 // erase the last line and resize the col
3015 //
3016 int cw, ch, dummy, top;
3017 m_gridWin->GetClientSize( &cw, &ch );
3018 CalcUnscrolledPosition( 0, 0, &dummy, &top );
3019
3020 wxClientDC dc( m_gridWin );
3021 PrepareDC( dc );
3022 dc.SetLogicalFunction( wxINVERT );
3023 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
3024 HideCellEditControl();
3025
3026 int colLeft = m_colRights[m_dragRowOrCol] - m_colWidths[m_dragRowOrCol];
3027 SetColSize( m_dragRowOrCol,
3028 wxMax( m_dragLastPos - colLeft, WXGRID_MIN_COL_WIDTH ) );
3029
3030 if ( !GetBatchCount() )
3031 {
3032 // Only needed to get the correct rect.x:
3033 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
3034 rect.y = 0;
3035 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
3036 rect.width = cw - rect.x;
3037 rect.height = m_colLabelHeight;
3038 m_colLabelWin->Refresh( TRUE, &rect );
3039 rect.height = ch;
3040 m_gridWin->Refresh( FALSE, &rect );
3041 }
3042
3043 ShowCellEditControl();
3044 }
3045 }
3046
3047
3048
3049 //
3050 // ------ interaction with data model
3051 //
3052 bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
3053 {
3054 switch ( msg.GetId() )
3055 {
3056 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
3057 return GetModelValues();
3058
3059 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
3060 return SetModelValues();
3061
3062 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
3063 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
3064 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
3065 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
3066 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
3067 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
3068 return Redimension( msg );
3069
3070 default:
3071 return FALSE;
3072 }
3073 }
3074
3075
3076
3077 // The behaviour of this function depends on the grid table class
3078 // Clear() function. For the default wxGridStringTable class the
3079 // behavious is to replace all cell contents with wxEmptyString but
3080 // not to change the number of rows or cols.
3081 //
3082 void wxGrid::ClearGrid()
3083 {
3084 if ( m_table )
3085 {
3086 m_table->Clear();
3087 SetEditControlValue();
3088 if ( !GetBatchCount() ) m_gridWin->Refresh();
3089 }
3090 }
3091
3092
3093 bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
3094 {
3095 // TODO: something with updateLabels flag
3096
3097 if ( !m_created )
3098 {
3099 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
3100 return FALSE;
3101 }
3102
3103 if ( m_table )
3104 {
3105 bool ok = m_table->InsertRows( pos, numRows );
3106
3107 // the table will have sent the results of the insert row
3108 // operation to this view object as a grid table message
3109 //
3110 if ( ok )
3111 {
3112 if ( m_numCols == 0 )
3113 {
3114 m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
3115 //
3116 // TODO: perhaps instead of appending the default number of cols
3117 // we should remember what the last non-zero number of cols was ?
3118 //
3119 }
3120
3121 if ( m_currentCellCoords == wxGridNoCellCoords )
3122 {
3123 // if we have just inserted cols into an empty grid the current
3124 // cell will be undefined...
3125 //
3126 SetCurrentCell( 0, 0 );
3127 }
3128
3129 ClearSelection();
3130 if ( !GetBatchCount() ) Refresh();
3131 }
3132
3133 SetEditControlValue();
3134 return ok;
3135 }
3136 else
3137 {
3138 return FALSE;
3139 }
3140 }
3141
3142
3143 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
3144 {
3145 // TODO: something with updateLabels flag
3146
3147 if ( !m_created )
3148 {
3149 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
3150 return FALSE;
3151 }
3152
3153 if ( m_table && m_table->AppendRows( numRows ) )
3154 {
3155 if ( m_currentCellCoords == wxGridNoCellCoords )
3156 {
3157 // if we have just inserted cols into an empty grid the current
3158 // cell will be undefined...
3159 //
3160 SetCurrentCell( 0, 0 );
3161 }
3162
3163 // the table will have sent the results of the append row
3164 // operation to this view object as a grid table message
3165 //
3166 ClearSelection();
3167 if ( !GetBatchCount() ) Refresh();
3168 return TRUE;
3169 }
3170 else
3171 {
3172 return FALSE;
3173 }
3174 }
3175
3176
3177 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
3178 {
3179 // TODO: something with updateLabels flag
3180
3181 if ( !m_created )
3182 {
3183 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
3184 return FALSE;
3185 }
3186
3187 if ( m_table && m_table->DeleteRows( pos, numRows ) )
3188 {
3189 // the table will have sent the results of the delete row
3190 // operation to this view object as a grid table message
3191 //
3192 if ( m_numRows > 0 )
3193 SetEditControlValue();
3194 else
3195 HideCellEditControl();
3196
3197 ClearSelection();
3198 if ( !GetBatchCount() ) Refresh();
3199 return TRUE;
3200 }
3201 else
3202 {
3203 return FALSE;
3204 }
3205 }
3206
3207
3208 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
3209 {
3210 // TODO: something with updateLabels flag
3211
3212 if ( !m_created )
3213 {
3214 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
3215 return FALSE;
3216 }
3217
3218 if ( m_table )
3219 {
3220 HideCellEditControl();
3221 bool ok = m_table->InsertCols( pos, numCols );
3222
3223 // the table will have sent the results of the insert col
3224 // operation to this view object as a grid table message
3225 //
3226 if ( ok )
3227 {
3228 if ( m_currentCellCoords == wxGridNoCellCoords )
3229 {
3230 // if we have just inserted cols into an empty grid the current
3231 // cell will be undefined...
3232 //
3233 SetCurrentCell( 0, 0 );
3234 }
3235
3236 ClearSelection();
3237 if ( !GetBatchCount() ) Refresh();
3238 }
3239
3240 SetEditControlValue();
3241 return ok;
3242 }
3243 else
3244 {
3245 return FALSE;
3246 }
3247 }
3248
3249
3250 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
3251 {
3252 // TODO: something with updateLabels flag
3253
3254 if ( !m_created )
3255 {
3256 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
3257 return FALSE;
3258 }
3259
3260 if ( m_table && m_table->AppendCols( numCols ) )
3261 {
3262 // the table will have sent the results of the append col
3263 // operation to this view object as a grid table message
3264 //
3265 if ( m_currentCellCoords == wxGridNoCellCoords )
3266 {
3267 // if we have just inserted cols into an empty grid the current
3268 // cell will be undefined...
3269 //
3270 SetCurrentCell( 0, 0 );
3271 }
3272
3273 ClearSelection();
3274 if ( !GetBatchCount() ) Refresh();
3275 return TRUE;
3276 }
3277 else
3278 {
3279 return FALSE;
3280 }
3281 }
3282
3283
3284 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
3285 {
3286 // TODO: something with updateLabels flag
3287
3288 if ( !m_created )
3289 {
3290 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
3291 return FALSE;
3292 }
3293
3294 if ( m_table && m_table->DeleteCols( pos, numCols ) )
3295 {
3296 // the table will have sent the results of the delete col
3297 // operation to this view object as a grid table message
3298 //
3299 if ( m_numCols > 0 )
3300 SetEditControlValue();
3301 else
3302 HideCellEditControl();
3303
3304 ClearSelection();
3305 if ( !GetBatchCount() ) Refresh();
3306 return TRUE;
3307 }
3308 else
3309 {
3310 return FALSE;
3311 }
3312 }
3313
3314
3315
3316 //
3317 // ----- event handlers
3318 //
3319
3320 // Generate a grid event based on a mouse event and
3321 // return the result of ProcessEvent()
3322 //
3323 bool wxGrid::SendEvent( const wxEventType type,
3324 int row, int col,
3325 wxMouseEvent& mouseEv )
3326 {
3327 if ( type == EVT_GRID_ROW_SIZE ||
3328 type == EVT_GRID_COL_SIZE )
3329 {
3330 int rowOrCol = (row == -1 ? col : row);
3331
3332 wxGridSizeEvent gridEvt( GetId(),
3333 type,
3334 this,
3335 rowOrCol,
3336 mouseEv.GetX(), mouseEv.GetY(),
3337 mouseEv.ControlDown(),
3338 mouseEv.ShiftDown(),
3339 mouseEv.AltDown(),
3340 mouseEv.MetaDown() );
3341
3342 return GetEventHandler()->ProcessEvent(gridEvt);
3343 }
3344 else if ( type == EVT_GRID_RANGE_SELECT )
3345 {
3346 wxGridRangeSelectEvent gridEvt( GetId(),
3347 type,
3348 this,
3349 m_selectedTopLeft,
3350 m_selectedBottomRight,
3351 mouseEv.ControlDown(),
3352 mouseEv.ShiftDown(),
3353 mouseEv.AltDown(),
3354 mouseEv.MetaDown() );
3355
3356 return GetEventHandler()->ProcessEvent(gridEvt);
3357 }
3358 else
3359 {
3360 wxGridEvent gridEvt( GetId(),
3361 type,
3362 this,
3363 row, col,
3364 mouseEv.GetX(), mouseEv.GetY(),
3365 mouseEv.ControlDown(),
3366 mouseEv.ShiftDown(),
3367 mouseEv.AltDown(),
3368 mouseEv.MetaDown() );
3369
3370 return GetEventHandler()->ProcessEvent(gridEvt);
3371 }
3372 }
3373
3374
3375 // Generate a grid event of specified type and return the result
3376 // of ProcessEvent().
3377 //
3378 bool wxGrid::SendEvent( const wxEventType type,
3379 int row, int col )
3380 {
3381 if ( type == EVT_GRID_ROW_SIZE ||
3382 type == EVT_GRID_COL_SIZE )
3383 {
3384 int rowOrCol = (row == -1 ? col : row);
3385
3386 wxGridSizeEvent gridEvt( GetId(),
3387 type,
3388 this,
3389 rowOrCol );
3390
3391 return GetEventHandler()->ProcessEvent(gridEvt);
3392 }
3393 else
3394 {
3395 wxGridEvent gridEvt( GetId(),
3396 type,
3397 this,
3398 row, col );
3399
3400 return GetEventHandler()->ProcessEvent(gridEvt);
3401 }
3402 }
3403
3404
3405 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
3406 {
3407 wxPaintDC dc( this );
3408
3409 if ( m_currentCellCoords == wxGridNoCellCoords &&
3410 m_numRows && m_numCols )
3411 {
3412 m_currentCellCoords.Set(0, 0);
3413 SetEditControlValue();
3414 ShowCellEditControl();
3415 }
3416
3417 m_displayed = TRUE;
3418 }
3419
3420
3421 // This is just here to make sure that CalcDimensions gets called when
3422 // the grid view is resized... then the size event is skipped to allow
3423 // the box sizers to handle everything
3424 //
3425 void wxGrid::OnSize( wxSizeEvent& event )
3426 {
3427 CalcWindowSizes();
3428 CalcDimensions();
3429 }
3430
3431
3432 void wxGrid::OnKeyDown( wxKeyEvent& event )
3433 {
3434 if ( m_inOnKeyDown )
3435 {
3436 // shouldn't be here - we are going round in circles...
3437 //
3438 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while alread active") );
3439 }
3440
3441 m_inOnKeyDown = TRUE;
3442
3443 // propagate the event up and see if it gets processed
3444 //
3445 wxWindow *parent = GetParent();
3446 wxKeyEvent keyEvt( event );
3447 keyEvt.SetEventObject( parent );
3448
3449 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
3450 {
3451 // try local handlers
3452 //
3453 switch ( event.KeyCode() )
3454 {
3455 case WXK_UP:
3456 if ( event.ControlDown() )
3457 {
3458 MoveCursorUpBlock();
3459 }
3460 else
3461 {
3462 MoveCursorUp();
3463 }
3464 break;
3465
3466 case WXK_DOWN:
3467 if ( event.ControlDown() )
3468 {
3469 MoveCursorDownBlock();
3470 }
3471 else
3472 {
3473 MoveCursorDown();
3474 }
3475 break;
3476
3477 case WXK_LEFT:
3478 if ( event.ControlDown() )
3479 {
3480 MoveCursorLeftBlock();
3481 }
3482 else
3483 {
3484 MoveCursorLeft();
3485 }
3486 break;
3487
3488 case WXK_RIGHT:
3489 if ( event.ControlDown() )
3490 {
3491 MoveCursorRightBlock();
3492 }
3493 else
3494 {
3495 MoveCursorRight();
3496 }
3497 break;
3498
3499 case WXK_SPACE:
3500 if ( !IsEditable() )
3501 {
3502 MoveCursorRight();
3503 }
3504 else
3505 {
3506 event.Skip();
3507 }
3508 break;
3509
3510 case WXK_RETURN:
3511 if ( event.ControlDown() )
3512 {
3513 event.Skip(); // to let the edit control have the return
3514 }
3515 else
3516 {
3517 MoveCursorDown();
3518 }
3519 break;
3520
3521 case WXK_HOME:
3522 if ( event.ControlDown() )
3523 {
3524 MakeCellVisible( 0, 0 );
3525 SetCurrentCell( 0, 0 );
3526 }
3527 else
3528 {
3529 event.Skip();
3530 }
3531 break;
3532
3533 case WXK_END:
3534 if ( event.ControlDown() )
3535 {
3536 MakeCellVisible( m_numRows-1, m_numCols-1 );
3537 SetCurrentCell( m_numRows-1, m_numCols-1 );
3538 }
3539 else
3540 {
3541 event.Skip();
3542 }
3543 break;
3544
3545 case WXK_PRIOR:
3546 MovePageUp();
3547 break;
3548
3549 case WXK_NEXT:
3550 MovePageDown();
3551 break;
3552
3553 default:
3554 // now try the cell edit control
3555 //
3556 if ( !IsCellEditControlEnabled() )
3557 EnableCellEditControl( TRUE );
3558 if ( IsCellEditControlEnabled() )
3559 {
3560 event.SetEventObject( m_cellEditCtrl );
3561 m_cellEditCtrl->GetEventHandler()->ProcessEvent( event );
3562 }
3563 break;
3564 }
3565 }
3566
3567 m_inOnKeyDown = FALSE;
3568 }
3569
3570 void wxGrid::OnEraseBackground(wxEraseEvent&)
3571 { }
3572
3573 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
3574 {
3575 if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
3576 {
3577 // the event has been intercepted - do nothing
3578 return;
3579 }
3580
3581 if ( m_displayed &&
3582 m_currentCellCoords != wxGridNoCellCoords )
3583 {
3584 HideCellEditControl();
3585 SaveEditControlValue();
3586 }
3587
3588 m_currentCellCoords = coords;
3589
3590 SetEditControlValue();
3591 #if 0
3592 if ( m_displayed )
3593 {
3594 ShowCellEditControl();
3595
3596 if ( IsSelection() )
3597 {
3598 wxRect r( SelectionToDeviceRect() );
3599 ClearSelection();
3600 if ( !GetBatchCount() ) m_gridWin->Refresh( FALSE, &r );
3601 }
3602 }
3603 #else
3604 SelectBlock ( coords, coords );
3605 #endif
3606 }
3607
3608
3609 //
3610 // ------ functions to get/send data (see also public functions)
3611 //
3612
3613 bool wxGrid::GetModelValues()
3614 {
3615 if ( m_table )
3616 {
3617 // all we need to do is repaint the grid
3618 //
3619 m_gridWin->Refresh();
3620 return TRUE;
3621 }
3622
3623 return FALSE;
3624 }
3625
3626
3627 bool wxGrid::SetModelValues()
3628 {
3629 int row, col;
3630
3631 if ( m_table )
3632 {
3633 for ( row = 0; row < m_numRows; row++ )
3634 {
3635 for ( col = 0; col < m_numCols; col++ )
3636 {
3637 m_table->SetValue( row, col, GetCellValue(row, col) );
3638 }
3639 }
3640
3641 return TRUE;
3642 }
3643
3644 return FALSE;
3645 }
3646
3647
3648
3649 // Note - this function only draws cells that are in the list of
3650 // exposed cells (usually set from the update region by
3651 // CalcExposedCells)
3652 //
3653 void wxGrid::DrawGridCellArea( wxDC& dc )
3654 {
3655 if ( !m_numRows || !m_numCols ) return;
3656
3657 size_t i;
3658 size_t numCells = m_cellsExposed.GetCount();
3659
3660 for ( i = 0; i < numCells; i++ )
3661 {
3662 DrawCell( dc, m_cellsExposed[i] );
3663 }
3664 }
3665
3666
3667 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
3668 {
3669 int row = coords.GetRow();
3670 int col = coords.GetCol();
3671
3672 if ( m_colWidths[col] <= 0 || m_rowHeights[row] <= 0 )
3673 return;
3674
3675 // we draw the cell border ourselves
3676 #if !WXGRID_DRAW_LINES
3677 if ( m_gridLinesEnabled )
3678 DrawCellBorder( dc, coords );
3679 #endif
3680
3681 // but all the rest is drawn by the cell renderer and hence may be
3682 // customized
3683 wxRect rect;
3684 rect.x = m_colRights[col] - m_colWidths[col];
3685 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3686 rect.width = m_colWidths[col] - 1;
3687 rect.height = m_rowHeights[row] - 1;
3688
3689 wxGridCellAttr* attr = GetCellAttr(row, col);
3690 attr->GetRenderer()->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
3691 attr->DecRef();
3692 }
3693
3694 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
3695 {
3696 if ( m_colWidths[coords.GetCol()] <=0 ||
3697 m_rowHeights[coords.GetRow()] <= 0 ) return;
3698
3699 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3700 int row = coords.GetRow();
3701 int col = coords.GetCol();
3702
3703 // right hand border
3704 //
3705 dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
3706 m_colRights[col], m_rowBottoms[row] );
3707
3708 // bottom border
3709 //
3710 dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
3711 m_colRights[col], m_rowBottoms[row] );
3712 }
3713
3714
3715 // TODO: remove this ???
3716 // This is used to redraw all grid lines e.g. when the grid line colour
3717 // has been changed
3718 //
3719 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg )
3720 {
3721 if ( !m_gridLinesEnabled ||
3722 !m_numRows ||
3723 !m_numCols ) return;
3724
3725 int top, bottom, left, right;
3726
3727 if (reg.IsEmpty()){
3728 int cw, ch;
3729 m_gridWin->GetClientSize(&cw, &ch);
3730
3731 // virtual coords of visible area
3732 //
3733 CalcUnscrolledPosition( 0, 0, &left, &top );
3734 CalcUnscrolledPosition( cw, ch, &right, &bottom );
3735 }
3736 else{
3737 wxCoord x, y, w, h;
3738 reg.GetBox(x, y, w, h);
3739 CalcUnscrolledPosition( x, y, &left, &top );
3740 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
3741 }
3742
3743 // avoid drawing grid lines past the last row and col
3744 //
3745 right = wxMin( right, m_colRights[m_numCols-1] );
3746 bottom = wxMin( bottom, m_rowBottoms[m_numRows-1] );
3747
3748 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3749
3750 // horizontal grid lines
3751 //
3752 int i;
3753 for ( i = 0; i < m_numRows; i++ )
3754 {
3755 if ( m_rowBottoms[i]-1 > bottom )
3756 {
3757 break;
3758 }
3759 else if ( m_rowBottoms[i]-1 >= top )
3760 {
3761 dc.DrawLine( left, m_rowBottoms[i]-1, right, m_rowBottoms[i]-1 );
3762 }
3763 }
3764
3765
3766 // vertical grid lines
3767 //
3768 for ( i = 0; i < m_numCols; i++ )
3769 {
3770 if ( m_colRights[i]-1 > right )
3771 {
3772 break;
3773 }
3774 else if ( m_colRights[i]-1 >= left )
3775 {
3776 dc.DrawLine( m_colRights[i]-1, top, m_colRights[i]-1, bottom );
3777 }
3778 }
3779 }
3780
3781
3782 void wxGrid::DrawRowLabels( wxDC& dc )
3783 {
3784 if ( !m_numRows || !m_numCols ) return;
3785
3786 size_t i;
3787 size_t numLabels = m_rowLabelsExposed.GetCount();
3788
3789 for ( i = 0; i < numLabels; i++ )
3790 {
3791 DrawRowLabel( dc, m_rowLabelsExposed[i] );
3792 }
3793 }
3794
3795
3796 void wxGrid::DrawRowLabel( wxDC& dc, int row )
3797 {
3798 if ( m_rowHeights[row] <= 0 ) return;
3799
3800 int rowTop = m_rowBottoms[row] - m_rowHeights[row];
3801
3802 dc.SetPen( *wxBLACK_PEN );
3803 dc.DrawLine( m_rowLabelWidth-1, rowTop,
3804 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3805
3806 dc.DrawLine( 0, m_rowBottoms[row]-1,
3807 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3808
3809 dc.SetPen( *wxWHITE_PEN );
3810 dc.DrawLine( 0, rowTop, 0, m_rowBottoms[row]-1 );
3811 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
3812
3813 dc.SetBackgroundMode( wxTRANSPARENT );
3814 dc.SetTextForeground( GetLabelTextColour() );
3815 dc.SetFont( GetLabelFont() );
3816
3817 int hAlign, vAlign;
3818 GetRowLabelAlignment( &hAlign, &vAlign );
3819
3820 wxRect rect;
3821 rect.SetX( 2 );
3822 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
3823 rect.SetWidth( m_rowLabelWidth - 4 );
3824 rect.SetHeight( m_rowHeights[row] - 4 );
3825 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
3826 }
3827
3828
3829 void wxGrid::DrawColLabels( wxDC& dc )
3830 {
3831 if ( !m_numRows || !m_numCols ) return;
3832
3833 size_t i;
3834 size_t numLabels = m_colLabelsExposed.GetCount();
3835
3836 for ( i = 0; i < numLabels; i++ )
3837 {
3838 DrawColLabel( dc, m_colLabelsExposed[i] );
3839 }
3840 }
3841
3842
3843 void wxGrid::DrawColLabel( wxDC& dc, int col )
3844 {
3845 if ( m_colWidths[col] <= 0 ) return;
3846
3847 int colLeft = m_colRights[col] - m_colWidths[col];
3848
3849 dc.SetPen( *wxBLACK_PEN );
3850 dc.DrawLine( m_colRights[col]-1, 0,
3851 m_colRights[col]-1, m_colLabelHeight-1 );
3852
3853 dc.DrawLine( colLeft, m_colLabelHeight-1,
3854 m_colRights[col]-1, m_colLabelHeight-1 );
3855
3856 dc.SetPen( *wxWHITE_PEN );
3857 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
3858 dc.DrawLine( colLeft, 0, m_colRights[col]-1, 0 );
3859
3860 dc.SetBackgroundMode( wxTRANSPARENT );
3861 dc.SetTextForeground( GetLabelTextColour() );
3862 dc.SetFont( GetLabelFont() );
3863
3864 dc.SetBackgroundMode( wxTRANSPARENT );
3865 dc.SetTextForeground( GetLabelTextColour() );
3866 dc.SetFont( GetLabelFont() );
3867
3868 int hAlign, vAlign;
3869 GetColLabelAlignment( &hAlign, &vAlign );
3870
3871 wxRect rect;
3872 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
3873 rect.SetY( 2 );
3874 rect.SetWidth( m_colWidths[col] - 4 );
3875 rect.SetHeight( m_colLabelHeight - 4 );
3876 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
3877 }
3878
3879
3880 void wxGrid::DrawTextRectangle( wxDC& dc,
3881 const wxString& value,
3882 const wxRect& rect,
3883 int horizAlign,
3884 int vertAlign )
3885 {
3886 long textWidth, textHeight;
3887 long lineWidth, lineHeight;
3888 wxArrayString lines;
3889
3890 dc.SetClippingRegion( rect );
3891 StringToLines( value, lines );
3892 if ( lines.GetCount() )
3893 {
3894 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
3895 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
3896
3897 float x, y;
3898 switch ( horizAlign )
3899 {
3900 case wxRIGHT:
3901 x = rect.x + (rect.width - textWidth - 1);
3902 break;
3903
3904 case wxCENTRE:
3905 x = rect.x + ((rect.width - textWidth)/2);
3906 break;
3907
3908 case wxLEFT:
3909 default:
3910 x = rect.x + 1;
3911 break;
3912 }
3913
3914 switch ( vertAlign )
3915 {
3916 case wxBOTTOM:
3917 y = rect.y + (rect.height - textHeight - 1);
3918 break;
3919
3920 case wxCENTRE:
3921 y = rect.y + ((rect.height - textHeight)/2);
3922 break;
3923
3924 case wxTOP:
3925 default:
3926 y = rect.y + 1;
3927 break;
3928 }
3929
3930 for ( size_t i = 0; i < lines.GetCount(); i++ )
3931 {
3932 dc.DrawText( lines[i], (long)x, (long)y );
3933 y += lineHeight;
3934 }
3935 }
3936
3937 dc.DestroyClippingRegion();
3938 }
3939
3940
3941 // Split multi line text up into an array of strings. Any existing
3942 // contents of the string array are preserved.
3943 //
3944 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
3945 {
3946 int startPos = 0;
3947 int pos;
3948 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
3949 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
3950
3951 while ( startPos < (int)tVal.Length() )
3952 {
3953 pos = tVal.Mid(startPos).Find( eol );
3954 if ( pos < 0 )
3955 {
3956 break;
3957 }
3958 else if ( pos == 0 )
3959 {
3960 lines.Add( wxEmptyString );
3961 }
3962 else
3963 {
3964 lines.Add( value.Mid(startPos, pos) );
3965 }
3966 startPos += pos+1;
3967 }
3968 if ( startPos < (int)value.Length() )
3969 {
3970 lines.Add( value.Mid( startPos ) );
3971 }
3972 }
3973
3974
3975 void wxGrid::GetTextBoxSize( wxDC& dc,
3976 wxArrayString& lines,
3977 long *width, long *height )
3978 {
3979 long w = 0;
3980 long h = 0;
3981 long lineW, lineH;
3982
3983 size_t i;
3984 for ( i = 0; i < lines.GetCount(); i++ )
3985 {
3986 dc.GetTextExtent( lines[i], &lineW, &lineH );
3987 w = wxMax( w, lineW );
3988 h += lineH;
3989 }
3990
3991 *width = w;
3992 *height = h;
3993 }
3994
3995
3996 //
3997 // ------ Edit control functions
3998 //
3999
4000
4001 void wxGrid::EnableEditing( bool edit )
4002 {
4003 // TODO: improve this ?
4004 //
4005 if ( edit != m_editable )
4006 {
4007 m_editable = edit;
4008
4009 // TODO: extend this for other edit control types
4010 //
4011 if ( m_editCtrlType == wxGRID_TEXTCTRL )
4012 {
4013 ((wxTextCtrl *)m_cellEditCtrl)->SetEditable( m_editable );
4014 }
4015 }
4016 }
4017
4018
4019 void wxGrid::EnableCellEditControl( bool enable )
4020 {
4021 if ( m_currentCellCoords == wxGridNoCellCoords )
4022 SetCurrentCell( 0, 0 );
4023 if ( m_cellEditCtrl &&
4024 enable != m_cellEditCtrlEnabled )
4025 {
4026
4027 if ( enable )
4028 {
4029 m_cellEditCtrlEnabled = enable;
4030 SetEditControlValue();
4031 // requires m_cellEditCtrlEnabled to be already true
4032 ShowCellEditControl();
4033 }
4034 else
4035 {
4036 HideCellEditControl();
4037 // requires m_cellEditCtrlEnabled to be still true
4038 SaveEditControlValue();
4039 m_cellEditCtrlEnabled = enable;
4040 }
4041 }
4042 }
4043
4044
4045 void wxGrid::ShowCellEditControl()
4046 {
4047 wxRect rect;
4048
4049 if ( IsCellEditControlEnabled() )
4050 {
4051 if ( !IsVisible( m_currentCellCoords ) )
4052 {
4053 return;
4054 }
4055 else
4056 {
4057 rect = CellToRect( m_currentCellCoords );
4058
4059 // convert to scrolled coords
4060 //
4061 int left, top, right, bottom;
4062 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
4063 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
4064
4065 int cw, ch;
4066 m_gridWin->GetClientSize( &cw, &ch );
4067
4068 // Make the edit control large enough to allow for internal margins
4069 // TODO: remove this if the text ctrl sizing is improved esp. for unix
4070 //
4071 int extra;
4072 #if defined(__WXMOTIF__)
4073 if ( m_currentCellCoords.GetRow() == 0 ||
4074 m_currentCellCoords.GetCol() == 0 )
4075 {
4076 extra = 2;
4077 }
4078 else
4079 {
4080 extra = 4;
4081 }
4082 #else
4083 if ( m_currentCellCoords.GetRow() == 0 ||
4084 m_currentCellCoords.GetCol() == 0 )
4085 {
4086 extra = 1;
4087 }
4088 else
4089 {
4090 extra = 2;
4091 }
4092 #endif
4093
4094 #if defined(__WXGTK__)
4095 int top_diff = 0;
4096 int left_diff = 0;
4097 if (left != 0) left_diff++;
4098 if (top != 0) top_diff++;
4099 rect.SetLeft( left + left_diff );
4100 rect.SetTop( top + top_diff );
4101 rect.SetRight( rect.GetRight() - left_diff );
4102 rect.SetBottom( rect.GetBottom() - top_diff );
4103 #else
4104 rect.SetLeft( wxMax(0, left - extra) );
4105 rect.SetTop( wxMax(0, top - extra) );
4106 rect.SetRight( rect.GetRight() + 2*extra );
4107 rect.SetBottom( rect.GetBottom() + 2*extra );
4108 #endif
4109
4110 m_cellEditCtrl->SetSize( rect );
4111 m_cellEditCtrl->Show( TRUE );
4112
4113 switch ( m_editCtrlType )
4114 {
4115 case wxGRID_TEXTCTRL:
4116 ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd();
4117 break;
4118
4119 case wxGRID_CHECKBOX:
4120 // TODO: anything ???
4121 //
4122 break;
4123
4124 case wxGRID_CHOICE:
4125 // TODO: anything ???
4126 //
4127 break;
4128
4129 case wxGRID_COMBOBOX:
4130 // TODO: anything ???
4131 //
4132 break;
4133 }
4134
4135 m_cellEditCtrl->SetFocus();
4136 }
4137 }
4138 }
4139
4140
4141 void wxGrid::HideCellEditControl()
4142 {
4143 if ( IsCellEditControlEnabled() )
4144 {
4145 m_cellEditCtrl->Show( FALSE );
4146 SetFocus();
4147 }
4148 }
4149
4150
4151 void wxGrid::SetEditControlValue( const wxString& value )
4152 {
4153 if ( m_table )
4154 {
4155 wxString s;
4156 if ( !value )
4157 s = GetCellValue(m_currentCellCoords);
4158 else
4159 s = value;
4160
4161 if ( IsCellEditControlEnabled() )
4162 {
4163 switch ( m_editCtrlType )
4164 {
4165 case wxGRID_TEXTCTRL:
4166 ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s);
4167 break;
4168
4169 case wxGRID_CHECKBOX:
4170 // TODO: implement this
4171 //
4172 break;
4173
4174 case wxGRID_CHOICE:
4175 // TODO: implement this
4176 //
4177 break;
4178
4179 case wxGRID_COMBOBOX:
4180 // TODO: implement this
4181 //
4182 break;
4183 }
4184 }
4185 }
4186 }
4187
4188
4189 void wxGrid::SaveEditControlValue()
4190 {
4191 if ( m_table )
4192 {
4193 wxWindow *ctrl = (wxWindow *)NULL;
4194
4195 if ( IsCellEditControlEnabled() )
4196 {
4197 ctrl = m_cellEditCtrl;
4198 }
4199 else
4200 {
4201 return;
4202 }
4203
4204 bool valueChanged = FALSE;
4205
4206 switch ( m_editCtrlType )
4207 {
4208 case wxGRID_TEXTCTRL:
4209 valueChanged = (((wxGridTextCtrl *)ctrl)->GetValue() !=
4210 ((wxGridTextCtrl *)ctrl)->GetStartValue());
4211 SetCellValue( m_currentCellCoords,
4212 ((wxTextCtrl *) ctrl)->GetValue() );
4213 break;
4214
4215 case wxGRID_CHECKBOX:
4216 // TODO: implement this
4217 //
4218 break;
4219
4220 case wxGRID_CHOICE:
4221 // TODO: implement this
4222 //
4223 break;
4224
4225 case wxGRID_COMBOBOX:
4226 // TODO: implement this
4227 //
4228 break;
4229 }
4230
4231 if ( valueChanged )
4232 {
4233 SendEvent( EVT_GRID_CELL_CHANGE,
4234 m_currentCellCoords.GetRow(),
4235 m_currentCellCoords.GetCol() );
4236 }
4237 }
4238 }
4239
4240
4241 //
4242 // ------ Grid location functions
4243 // Note that all of these functions work with the logical coordinates of
4244 // grid cells and labels so you will need to convert from device
4245 // coordinates for mouse events etc.
4246 //
4247
4248 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
4249 {
4250 int row = YToRow(y);
4251 int col = XToCol(x);
4252
4253 if ( row == -1 || col == -1 )
4254 {
4255 coords = wxGridNoCellCoords;
4256 }
4257 else
4258 {
4259 coords.Set( row, col );
4260 }
4261 }
4262
4263
4264 int wxGrid::YToRow( int y )
4265 {
4266 int i;
4267
4268 for ( i = 0; i < m_numRows; i++ )
4269 {
4270 if ( y < m_rowBottoms[i] ) return i;
4271 }
4272
4273 return -1;
4274 }
4275
4276
4277 int wxGrid::XToCol( int x )
4278 {
4279 int i;
4280
4281 for ( i = 0; i < m_numCols; i++ )
4282 {
4283 if ( x < m_colRights[i] ) return i;
4284 }
4285
4286 return -1;
4287 }
4288
4289
4290 // return the row number that that the y coord is near the edge of, or
4291 // -1 if not near an edge
4292 //
4293 int wxGrid::YToEdgeOfRow( int y )
4294 {
4295 int i, d;
4296
4297 for ( i = 0; i < m_numRows; i++ )
4298 {
4299 if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
4300 {
4301 d = abs( y - m_rowBottoms[i] );
4302 {
4303 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
4304 }
4305 }
4306 }
4307
4308 return -1;
4309 }
4310
4311
4312 // return the col number that that the x coord is near the edge of, or
4313 // -1 if not near an edge
4314 //
4315 int wxGrid::XToEdgeOfCol( int x )
4316 {
4317 int i, d;
4318
4319 for ( i = 0; i < m_numCols; i++ )
4320 {
4321 if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
4322 {
4323 d = abs( x - m_colRights[i] );
4324 {
4325 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
4326 }
4327 }
4328 }
4329
4330 return -1;
4331 }
4332
4333
4334 wxRect wxGrid::CellToRect( int row, int col )
4335 {
4336 wxRect rect( -1, -1, -1, -1 );
4337
4338 if ( row >= 0 && row < m_numRows &&
4339 col >= 0 && col < m_numCols )
4340 {
4341 rect.x = m_colRights[col] - m_colWidths[col];
4342 rect.y = m_rowBottoms[row] - m_rowHeights[row];
4343 rect.width = m_colWidths[col];
4344 rect.height = m_rowHeights[ row ];
4345 }
4346
4347 return rect;
4348 }
4349
4350
4351 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
4352 {
4353 // get the cell rectangle in logical coords
4354 //
4355 wxRect r( CellToRect( row, col ) );
4356
4357 // convert to device coords
4358 //
4359 int left, top, right, bottom;
4360 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4361 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
4362
4363 // check against the client area of the grid window
4364 //
4365 int cw, ch;
4366 m_gridWin->GetClientSize( &cw, &ch );
4367
4368 if ( wholeCellVisible )
4369 {
4370 // is the cell wholly visible ?
4371 //
4372 return ( left >= 0 && right <= cw &&
4373 top >= 0 && bottom <= ch );
4374 }
4375 else
4376 {
4377 // is the cell partly visible ?
4378 //
4379 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
4380 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
4381 }
4382 }
4383
4384
4385 // make the specified cell location visible by doing a minimal amount
4386 // of scrolling
4387 //
4388 void wxGrid::MakeCellVisible( int row, int col )
4389 {
4390 int i;
4391 int xpos = -1, ypos = -1;
4392
4393 if ( row >= 0 && row < m_numRows &&
4394 col >= 0 && col < m_numCols )
4395 {
4396 // get the cell rectangle in logical coords
4397 //
4398 wxRect r( CellToRect( row, col ) );
4399
4400 // convert to device coords
4401 //
4402 int left, top, right, bottom;
4403 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4404 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
4405
4406 int cw, ch;
4407 m_gridWin->GetClientSize( &cw, &ch );
4408
4409 if ( top < 0 )
4410 {
4411 ypos = r.GetTop();
4412 }
4413 else if ( bottom > ch )
4414 {
4415 int h = r.GetHeight();
4416 ypos = r.GetTop();
4417 for ( i = row-1; i >= 0; i-- )
4418 {
4419 if ( h + m_rowHeights[i] > ch ) break;
4420
4421 h += m_rowHeights[i];
4422 ypos -= m_rowHeights[i];
4423 }
4424
4425 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
4426 // have rounding errors (this is important, because if we do, we
4427 // might not scroll at all and some cells won't be redrawn)
4428 ypos += GRID_SCROLL_LINE / 2;
4429 }
4430
4431 if ( left < 0 )
4432 {
4433 xpos = r.GetLeft();
4434 }
4435 else if ( right > cw )
4436 {
4437 int w = r.GetWidth();
4438 xpos = r.GetLeft();
4439 for ( i = col-1; i >= 0; i-- )
4440 {
4441 if ( w + m_colWidths[i] > cw ) break;
4442
4443 w += m_colWidths[i];
4444 xpos -= m_colWidths[i];
4445 }
4446
4447 // see comment for ypos above
4448 xpos += GRID_SCROLL_LINE / 2;
4449 }
4450
4451 if ( xpos != -1 || ypos != -1 )
4452 {
4453 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
4454 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
4455 Scroll( xpos, ypos );
4456 AdjustScrollbars();
4457 }
4458 }
4459 }
4460
4461
4462 //
4463 // ------ Grid cursor movement functions
4464 //
4465
4466 bool wxGrid::MoveCursorUp()
4467 {
4468 if ( m_currentCellCoords != wxGridNoCellCoords &&
4469 m_currentCellCoords.GetRow() > 0 )
4470 {
4471 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
4472 m_currentCellCoords.GetCol() );
4473
4474 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
4475 m_currentCellCoords.GetCol() );
4476
4477 return TRUE;
4478 }
4479
4480 return FALSE;
4481 }
4482
4483
4484 bool wxGrid::MoveCursorDown()
4485 {
4486 // TODO: allow for scrolling
4487 //
4488 if ( m_currentCellCoords != wxGridNoCellCoords &&
4489 m_currentCellCoords.GetRow() < m_numRows-1 )
4490 {
4491 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
4492 m_currentCellCoords.GetCol() );
4493
4494 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
4495 m_currentCellCoords.GetCol() );
4496
4497 return TRUE;
4498 }
4499
4500 return FALSE;
4501 }
4502
4503
4504 bool wxGrid::MoveCursorLeft()
4505 {
4506 if ( m_currentCellCoords != wxGridNoCellCoords &&
4507 m_currentCellCoords.GetCol() > 0 )
4508 {
4509 MakeCellVisible( m_currentCellCoords.GetRow(),
4510 m_currentCellCoords.GetCol() - 1 );
4511
4512 SetCurrentCell( m_currentCellCoords.GetRow(),
4513 m_currentCellCoords.GetCol() - 1 );
4514
4515 return TRUE;
4516 }
4517
4518 return FALSE;
4519 }
4520
4521
4522 bool wxGrid::MoveCursorRight()
4523 {
4524 if ( m_currentCellCoords != wxGridNoCellCoords &&
4525 m_currentCellCoords.GetCol() < m_numCols - 1 )
4526 {
4527 MakeCellVisible( m_currentCellCoords.GetRow(),
4528 m_currentCellCoords.GetCol() + 1 );
4529
4530 SetCurrentCell( m_currentCellCoords.GetRow(),
4531 m_currentCellCoords.GetCol() + 1 );
4532
4533 return TRUE;
4534 }
4535
4536 return FALSE;
4537 }
4538
4539
4540 bool wxGrid::MovePageUp()
4541 {
4542 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
4543
4544 int row = m_currentCellCoords.GetRow();
4545 if ( row > 0 )
4546 {
4547 int cw, ch;
4548 m_gridWin->GetClientSize( &cw, &ch );
4549
4550 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4551 int newRow = YToRow( y - ch + 1 );
4552 if ( newRow == -1 )
4553 {
4554 newRow = 0;
4555 }
4556 else if ( newRow == row )
4557 {
4558 newRow = row - 1;
4559 }
4560
4561 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4562 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
4563
4564 return TRUE;
4565 }
4566
4567 return FALSE;
4568 }
4569
4570 bool wxGrid::MovePageDown()
4571 {
4572 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
4573
4574 int row = m_currentCellCoords.GetRow();
4575 if ( row < m_numRows )
4576 {
4577 int cw, ch;
4578 m_gridWin->GetClientSize( &cw, &ch );
4579
4580 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4581 int newRow = YToRow( y + ch );
4582 if ( newRow == -1 )
4583 {
4584 newRow = m_numRows - 1;
4585 }
4586 else if ( newRow == row )
4587 {
4588 newRow = row + 1;
4589 }
4590
4591 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4592 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
4593
4594 return TRUE;
4595 }
4596
4597 return FALSE;
4598 }
4599
4600 bool wxGrid::MoveCursorUpBlock()
4601 {
4602 if ( m_table &&
4603 m_currentCellCoords != wxGridNoCellCoords &&
4604 m_currentCellCoords.GetRow() > 0 )
4605 {
4606 int row = m_currentCellCoords.GetRow();
4607 int col = m_currentCellCoords.GetCol();
4608
4609 if ( m_table->IsEmptyCell(row, col) )
4610 {
4611 // starting in an empty cell: find the next block of
4612 // non-empty cells
4613 //
4614 while ( row > 0 )
4615 {
4616 row-- ;
4617 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4618 }
4619 }
4620 else if ( m_table->IsEmptyCell(row-1, col) )
4621 {
4622 // starting at the top of a block: find the next block
4623 //
4624 row--;
4625 while ( row > 0 )
4626 {
4627 row-- ;
4628 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4629 }
4630 }
4631 else
4632 {
4633 // starting within a block: find the top of the block
4634 //
4635 while ( row > 0 )
4636 {
4637 row-- ;
4638 if ( m_table->IsEmptyCell(row, col) )
4639 {
4640 row++ ;
4641 break;
4642 }
4643 }
4644 }
4645
4646 MakeCellVisible( row, col );
4647 SetCurrentCell( row, col );
4648
4649 return TRUE;
4650 }
4651
4652 return FALSE;
4653 }
4654
4655 bool wxGrid::MoveCursorDownBlock()
4656 {
4657 if ( m_table &&
4658 m_currentCellCoords != wxGridNoCellCoords &&
4659 m_currentCellCoords.GetRow() < m_numRows-1 )
4660 {
4661 int row = m_currentCellCoords.GetRow();
4662 int col = m_currentCellCoords.GetCol();
4663
4664 if ( m_table->IsEmptyCell(row, col) )
4665 {
4666 // starting in an empty cell: find the next block of
4667 // non-empty cells
4668 //
4669 while ( row < m_numRows-1 )
4670 {
4671 row++ ;
4672 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4673 }
4674 }
4675 else if ( m_table->IsEmptyCell(row+1, col) )
4676 {
4677 // starting at the bottom of a block: find the next block
4678 //
4679 row++;
4680 while ( row < m_numRows-1 )
4681 {
4682 row++ ;
4683 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4684 }
4685 }
4686 else
4687 {
4688 // starting within a block: find the bottom of the block
4689 //
4690 while ( row < m_numRows-1 )
4691 {
4692 row++ ;
4693 if ( m_table->IsEmptyCell(row, col) )
4694 {
4695 row-- ;
4696 break;
4697 }
4698 }
4699 }
4700
4701 MakeCellVisible( row, col );
4702 SetCurrentCell( row, col );
4703
4704 return TRUE;
4705 }
4706
4707 return FALSE;
4708 }
4709
4710 bool wxGrid::MoveCursorLeftBlock()
4711 {
4712 if ( m_table &&
4713 m_currentCellCoords != wxGridNoCellCoords &&
4714 m_currentCellCoords.GetCol() > 0 )
4715 {
4716 int row = m_currentCellCoords.GetRow();
4717 int col = m_currentCellCoords.GetCol();
4718
4719 if ( m_table->IsEmptyCell(row, col) )
4720 {
4721 // starting in an empty cell: find the next block of
4722 // non-empty cells
4723 //
4724 while ( col > 0 )
4725 {
4726 col-- ;
4727 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4728 }
4729 }
4730 else if ( m_table->IsEmptyCell(row, col-1) )
4731 {
4732 // starting at the left of a block: find the next block
4733 //
4734 col--;
4735 while ( col > 0 )
4736 {
4737 col-- ;
4738 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4739 }
4740 }
4741 else
4742 {
4743 // starting within a block: find the left of the block
4744 //
4745 while ( col > 0 )
4746 {
4747 col-- ;
4748 if ( m_table->IsEmptyCell(row, col) )
4749 {
4750 col++ ;
4751 break;
4752 }
4753 }
4754 }
4755
4756 MakeCellVisible( row, col );
4757 SetCurrentCell( row, col );
4758
4759 return TRUE;
4760 }
4761
4762 return FALSE;
4763 }
4764
4765 bool wxGrid::MoveCursorRightBlock()
4766 {
4767 if ( m_table &&
4768 m_currentCellCoords != wxGridNoCellCoords &&
4769 m_currentCellCoords.GetCol() < m_numCols-1 )
4770 {
4771 int row = m_currentCellCoords.GetRow();
4772 int col = m_currentCellCoords.GetCol();
4773
4774 if ( m_table->IsEmptyCell(row, col) )
4775 {
4776 // starting in an empty cell: find the next block of
4777 // non-empty cells
4778 //
4779 while ( col < m_numCols-1 )
4780 {
4781 col++ ;
4782 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4783 }
4784 }
4785 else if ( m_table->IsEmptyCell(row, col+1) )
4786 {
4787 // starting at the right of a block: find the next block
4788 //
4789 col++;
4790 while ( col < m_numCols-1 )
4791 {
4792 col++ ;
4793 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4794 }
4795 }
4796 else
4797 {
4798 // starting within a block: find the right of the block
4799 //
4800 while ( col < m_numCols-1 )
4801 {
4802 col++ ;
4803 if ( m_table->IsEmptyCell(row, col) )
4804 {
4805 col-- ;
4806 break;
4807 }
4808 }
4809 }
4810
4811 MakeCellVisible( row, col );
4812 SetCurrentCell( row, col );
4813
4814 return TRUE;
4815 }
4816
4817 return FALSE;
4818 }
4819
4820
4821
4822 //
4823 // ------ Label values and formatting
4824 //
4825
4826 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
4827 {
4828 *horiz = m_rowLabelHorizAlign;
4829 *vert = m_rowLabelVertAlign;
4830 }
4831
4832 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
4833 {
4834 *horiz = m_colLabelHorizAlign;
4835 *vert = m_colLabelVertAlign;
4836 }
4837
4838 wxString wxGrid::GetRowLabelValue( int row )
4839 {
4840 if ( m_table )
4841 {
4842 return m_table->GetRowLabelValue( row );
4843 }
4844 else
4845 {
4846 wxString s;
4847 s << row;
4848 return s;
4849 }
4850 }
4851
4852 wxString wxGrid::GetColLabelValue( int col )
4853 {
4854 if ( m_table )
4855 {
4856 return m_table->GetColLabelValue( col );
4857 }
4858 else
4859 {
4860 wxString s;
4861 s << col;
4862 return s;
4863 }
4864 }
4865
4866
4867 void wxGrid::SetRowLabelSize( int width )
4868 {
4869 width = wxMax( width, 0 );
4870 if ( width != m_rowLabelWidth )
4871 {
4872 if ( width == 0 )
4873 {
4874 m_rowLabelWin->Show( FALSE );
4875 m_cornerLabelWin->Show( FALSE );
4876 }
4877 else if ( m_rowLabelWidth == 0 )
4878 {
4879 m_rowLabelWin->Show( TRUE );
4880 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
4881 }
4882
4883 m_rowLabelWidth = width;
4884 CalcWindowSizes();
4885 Refresh( TRUE );
4886 }
4887 }
4888
4889
4890 void wxGrid::SetColLabelSize( int height )
4891 {
4892 height = wxMax( height, 0 );
4893 if ( height != m_colLabelHeight )
4894 {
4895 if ( height == 0 )
4896 {
4897 m_colLabelWin->Show( FALSE );
4898 m_cornerLabelWin->Show( FALSE );
4899 }
4900 else if ( m_colLabelHeight == 0 )
4901 {
4902 m_colLabelWin->Show( TRUE );
4903 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
4904 }
4905
4906 m_colLabelHeight = height;
4907 CalcWindowSizes();
4908 Refresh( TRUE );
4909 }
4910 }
4911
4912
4913 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
4914 {
4915 if ( m_labelBackgroundColour != colour )
4916 {
4917 m_labelBackgroundColour = colour;
4918 m_rowLabelWin->SetBackgroundColour( colour );
4919 m_colLabelWin->SetBackgroundColour( colour );
4920 m_cornerLabelWin->SetBackgroundColour( colour );
4921
4922 if ( !GetBatchCount() )
4923 {
4924 m_rowLabelWin->Refresh();
4925 m_colLabelWin->Refresh();
4926 m_cornerLabelWin->Refresh();
4927 }
4928 }
4929 }
4930
4931 void wxGrid::SetLabelTextColour( const wxColour& colour )
4932 {
4933 if ( m_labelTextColour != colour )
4934 {
4935 m_labelTextColour = colour;
4936 if ( !GetBatchCount() )
4937 {
4938 m_rowLabelWin->Refresh();
4939 m_colLabelWin->Refresh();
4940 }
4941 }
4942 }
4943
4944 void wxGrid::SetLabelFont( const wxFont& font )
4945 {
4946 m_labelFont = font;
4947 if ( !GetBatchCount() )
4948 {
4949 m_rowLabelWin->Refresh();
4950 m_colLabelWin->Refresh();
4951 }
4952 }
4953
4954 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
4955 {
4956 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4957 {
4958 m_rowLabelHorizAlign = horiz;
4959 }
4960
4961 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4962 {
4963 m_rowLabelVertAlign = vert;
4964 }
4965
4966 if ( !GetBatchCount() )
4967 {
4968 m_rowLabelWin->Refresh();
4969 }
4970 }
4971
4972 void wxGrid::SetColLabelAlignment( int horiz, int vert )
4973 {
4974 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4975 {
4976 m_colLabelHorizAlign = horiz;
4977 }
4978
4979 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4980 {
4981 m_colLabelVertAlign = vert;
4982 }
4983
4984 if ( !GetBatchCount() )
4985 {
4986 m_colLabelWin->Refresh();
4987 }
4988 }
4989
4990 void wxGrid::SetRowLabelValue( int row, const wxString& s )
4991 {
4992 if ( m_table )
4993 {
4994 m_table->SetRowLabelValue( row, s );
4995 if ( !GetBatchCount() )
4996 {
4997 wxRect rect = CellToRect( row, 0);
4998 if ( rect.height > 0 )
4999 {
5000 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
5001 rect.x = m_left;
5002 rect.width = m_rowLabelWidth;
5003 m_rowLabelWin->Refresh( TRUE, &rect );
5004 }
5005 }
5006 }
5007 }
5008
5009 void wxGrid::SetColLabelValue( int col, const wxString& s )
5010 {
5011 if ( m_table )
5012 {
5013 m_table->SetColLabelValue( col, s );
5014 if ( !GetBatchCount() )
5015 {
5016 wxRect rect = CellToRect( 0, col );
5017 if ( rect.width > 0 )
5018 {
5019 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
5020 rect.y = m_top;
5021 rect.height = m_colLabelHeight;
5022 m_colLabelWin->Refresh( TRUE, &rect );
5023 }
5024 }
5025 }
5026 }
5027
5028 void wxGrid::SetGridLineColour( const wxColour& colour )
5029 {
5030 if ( m_gridLineColour != colour )
5031 {
5032 m_gridLineColour = colour;
5033
5034 wxClientDC dc( m_gridWin );
5035 PrepareDC( dc );
5036 DrawAllGridLines( dc, wxRegion() );
5037 }
5038 }
5039
5040 void wxGrid::EnableGridLines( bool enable )
5041 {
5042 if ( enable != m_gridLinesEnabled )
5043 {
5044 m_gridLinesEnabled = enable;
5045
5046 if ( !GetBatchCount() )
5047 {
5048 if ( enable )
5049 {
5050 wxClientDC dc( m_gridWin );
5051 PrepareDC( dc );
5052 DrawAllGridLines( dc, wxRegion() );
5053 }
5054 else
5055 {
5056 m_gridWin->Refresh();
5057 }
5058 }
5059 }
5060 }
5061
5062
5063 int wxGrid::GetDefaultRowSize()
5064 {
5065 return m_defaultRowHeight;
5066 }
5067
5068 int wxGrid::GetRowSize( int row )
5069 {
5070 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
5071
5072 return m_rowHeights[row];
5073 }
5074
5075 int wxGrid::GetDefaultColSize()
5076 {
5077 return m_defaultColWidth;
5078 }
5079
5080 int wxGrid::GetColSize( int col )
5081 {
5082 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
5083
5084 return m_colWidths[col];
5085 }
5086
5087 // ============================================================================
5088 // access to the grid attributes: each of them has a default value in the grid
5089 // itself and may be overidden on a per-cell basis
5090 // ============================================================================
5091
5092 // ----------------------------------------------------------------------------
5093 // setting default attributes
5094 // ----------------------------------------------------------------------------
5095
5096 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
5097 {
5098 m_defaultCellAttr->SetBackgroundColour(col);
5099 }
5100
5101 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
5102 {
5103 m_defaultCellAttr->SetTextColour(col);
5104 }
5105
5106 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
5107 {
5108 m_defaultCellAttr->SetAlignment(horiz, vert);
5109 }
5110
5111 void wxGrid::SetDefaultCellFont( const wxFont& font )
5112 {
5113 m_defaultCellAttr->SetFont(font);
5114 }
5115
5116 void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
5117 {
5118 m_defaultCellAttr->SetRenderer(renderer);
5119 }
5120
5121 // ----------------------------------------------------------------------------
5122 // access to the default attrbiutes
5123 // ----------------------------------------------------------------------------
5124
5125 wxColour wxGrid::GetDefaultCellBackgroundColour()
5126 {
5127 return m_defaultCellAttr->GetBackgroundColour();
5128 }
5129
5130 wxColour wxGrid::GetDefaultCellTextColour()
5131 {
5132 return m_defaultCellAttr->GetTextColour();
5133 }
5134
5135 wxFont wxGrid::GetDefaultCellFont()
5136 {
5137 return m_defaultCellAttr->GetFont();
5138 }
5139
5140 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
5141 {
5142 m_defaultCellAttr->GetAlignment(horiz, vert);
5143 }
5144
5145 wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
5146 {
5147 return m_defaultCellAttr->GetRenderer();
5148 }
5149
5150 // ----------------------------------------------------------------------------
5151 // access to cell attributes
5152 // ----------------------------------------------------------------------------
5153
5154 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
5155 {
5156 wxGridCellAttr *attr = GetCellAttr(row, col);
5157 wxColour colour = attr->GetBackgroundColour();
5158 attr->SafeDecRef();
5159 return colour;
5160 }
5161
5162 wxColour wxGrid::GetCellTextColour( int row, int col )
5163 {
5164 wxGridCellAttr *attr = GetCellAttr(row, col);
5165 wxColour colour = attr->GetTextColour();
5166 attr->SafeDecRef();
5167 return colour;
5168 }
5169
5170 wxFont wxGrid::GetCellFont( int row, int col )
5171 {
5172 wxGridCellAttr *attr = GetCellAttr(row, col);
5173 wxFont font = attr->GetFont();
5174 attr->SafeDecRef();
5175 return font;
5176 }
5177
5178 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
5179 {
5180 wxGridCellAttr *attr = GetCellAttr(row, col);
5181 attr->GetAlignment(horiz, vert);
5182 attr->SafeDecRef();
5183 }
5184
5185 wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
5186 {
5187 wxGridCellAttr* attr = GetCellAttr(row, col);
5188 wxGridCellRenderer* renderer = attr->GetRenderer();
5189 attr->DecRef();
5190 return renderer;
5191 }
5192
5193 // ----------------------------------------------------------------------------
5194 // attribute support: cache, automatic provider creation, ...
5195 // ----------------------------------------------------------------------------
5196
5197 bool wxGrid::CanHaveAttributes()
5198 {
5199 if ( !m_table )
5200 {
5201 return FALSE;
5202 }
5203
5204 // RD: Maybe m_table->CanHaveAttributes() would be better in case the
5205 // table is providing the attributes itself??? In which case
5206 // I don't think the grid should create a Provider object for the
5207 // table but the table should be smart enough to do that on its own.
5208 if ( !m_table->GetAttrProvider() )
5209 {
5210 // use the default attr provider by default
5211 // (another choice would be to just return FALSE thus forcing the user
5212 // to it himself)
5213 m_table->SetAttrProvider(new wxGridCellAttrProvider);
5214 }
5215
5216 return TRUE;
5217 }
5218
5219 void wxGrid::ClearAttrCache()
5220 {
5221 if ( m_attrCache.row != -1 )
5222 {
5223 m_attrCache.attr->SafeDecRef();
5224 m_attrCache.row = -1;
5225 }
5226 }
5227
5228 void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
5229 {
5230 wxGrid *self = (wxGrid *)this; // const_cast
5231
5232 self->ClearAttrCache();
5233 self->m_attrCache.row = row;
5234 self->m_attrCache.col = col;
5235 self->m_attrCache.attr = attr;
5236 attr->SafeIncRef();
5237 }
5238
5239 bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
5240 {
5241 if ( row == m_attrCache.row && col == m_attrCache.col )
5242 {
5243 *attr = m_attrCache.attr;
5244 (*attr)->SafeIncRef();
5245
5246 #ifdef DEBUG_ATTR_CACHE
5247 gs_nAttrCacheHits++;
5248 #endif
5249
5250 return TRUE;
5251 }
5252 else
5253 {
5254 #ifdef DEBUG_ATTR_CACHE
5255 gs_nAttrCacheMisses++;
5256 #endif
5257 return FALSE;
5258 }
5259 }
5260
5261 wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
5262 {
5263 wxGridCellAttr *attr;
5264 if ( !LookupAttr(row, col, &attr) )
5265 {
5266 attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
5267 CacheAttr(row, col, attr);
5268 }
5269 if (attr) {
5270 attr->SetDefAttr(m_defaultCellAttr);
5271 } else {
5272 attr = m_defaultCellAttr;
5273 attr->IncRef();
5274 }
5275
5276 return attr;
5277 }
5278
5279 wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
5280 {
5281 wxGridCellAttr *attr;
5282 if ( !LookupAttr(row, col, &attr) || !attr )
5283 {
5284 wxASSERT_MSG( m_table,
5285 _T("we may only be called if CanHaveAttributes() "
5286 "returned TRUE and then m_table should be !NULL") );
5287
5288 attr = m_table->GetAttr(row, col);
5289 if ( !attr )
5290 {
5291 attr = new wxGridCellAttr;
5292
5293 // artificially inc the ref count to match DecRef() in caller
5294 attr->IncRef();
5295
5296 m_table->SetAttr(attr, row, col);
5297 }
5298
5299 CacheAttr(row, col, attr);
5300 }
5301 attr->SetDefAttr(m_defaultCellAttr);
5302 return attr;
5303 }
5304
5305 // ----------------------------------------------------------------------------
5306 // setting cell attributes: this is forwarded to the table
5307 // ----------------------------------------------------------------------------
5308
5309 void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
5310 {
5311 if ( CanHaveAttributes() )
5312 {
5313 m_table->SetRowAttr(attr, row);
5314 }
5315 else
5316 {
5317 attr->SafeDecRef();
5318 }
5319 }
5320
5321 void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
5322 {
5323 if ( CanHaveAttributes() )
5324 {
5325 m_table->SetColAttr(attr, col);
5326 }
5327 else
5328 {
5329 attr->SafeDecRef();
5330 }
5331 }
5332
5333 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
5334 {
5335 if ( CanHaveAttributes() )
5336 {
5337 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5338 attr->SetBackgroundColour(colour);
5339 attr->DecRef();
5340 }
5341 }
5342
5343 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
5344 {
5345 if ( CanHaveAttributes() )
5346 {
5347 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5348 attr->SetTextColour(colour);
5349 attr->DecRef();
5350 }
5351 }
5352
5353 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
5354 {
5355 if ( CanHaveAttributes() )
5356 {
5357 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5358 attr->SetFont(font);
5359 attr->DecRef();
5360 }
5361 }
5362
5363 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
5364 {
5365 if ( CanHaveAttributes() )
5366 {
5367 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5368 attr->SetAlignment(horiz, vert);
5369 attr->DecRef();
5370 }
5371 }
5372
5373 void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
5374 {
5375 if ( CanHaveAttributes() )
5376 {
5377 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5378 attr->SetRenderer(renderer);
5379 attr->DecRef();
5380 }
5381 }
5382
5383 // ----------------------------------------------------------------------------
5384 // row/col size
5385 // ----------------------------------------------------------------------------
5386
5387 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
5388 {
5389 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
5390
5391 if ( resizeExistingRows )
5392 {
5393 int row;
5394 int bottom = 0;
5395 for ( row = 0; row < m_numRows; row++ )
5396 {
5397 m_rowHeights[row] = m_defaultRowHeight;
5398 bottom += m_defaultRowHeight;
5399 m_rowBottoms[row] = bottom;
5400 }
5401 CalcDimensions();
5402 }
5403 }
5404
5405 void wxGrid::SetRowSize( int row, int height )
5406 {
5407 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
5408
5409 int i;
5410
5411 int h = wxMax( 0, height );
5412 int diff = h - m_rowHeights[row];
5413
5414 m_rowHeights[row] = h;
5415 for ( i = row; i < m_numRows; i++ )
5416 {
5417 m_rowBottoms[i] += diff;
5418 }
5419 CalcDimensions();
5420 }
5421
5422 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
5423 {
5424 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
5425
5426 if ( resizeExistingCols )
5427 {
5428 int col;
5429 int right = 0;
5430 for ( col = 0; col < m_numCols; col++ )
5431 {
5432 m_colWidths[col] = m_defaultColWidth;
5433 right += m_defaultColWidth;
5434 m_colRights[col] = right;
5435 }
5436 CalcDimensions();
5437 }
5438 }
5439
5440 void wxGrid::SetColSize( int col, int width )
5441 {
5442 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
5443
5444 int i;
5445
5446 int w = wxMax( 0, width );
5447 int diff = w - m_colWidths[col];
5448 m_colWidths[col] = w;
5449
5450 for ( i = col; i < m_numCols; i++ )
5451 {
5452 m_colRights[i] += diff;
5453 }
5454 CalcDimensions();
5455 }
5456
5457
5458 //
5459 // ------ cell value accessor functions
5460 //
5461
5462 void wxGrid::SetCellValue( int row, int col, const wxString& s )
5463 {
5464 if ( m_table )
5465 {
5466 m_table->SetValue( row, col, s.c_str() );
5467 if ( !GetBatchCount() )
5468 {
5469 wxClientDC dc( m_gridWin );
5470 PrepareDC( dc );
5471 DrawCell( dc, wxGridCellCoords(row, col) );
5472 }
5473
5474 #if 0 // TODO: edit in place
5475
5476 if ( m_currentCellCoords.GetRow() == row &&
5477 m_currentCellCoords.GetCol() == col )
5478 {
5479 SetEditControlValue( s );
5480 }
5481 #endif
5482
5483 }
5484 }
5485
5486
5487 //
5488 // ------ Block, row and col selection
5489 //
5490
5491 void wxGrid::SelectRow( int row, bool addToSelected )
5492 {
5493 wxRect r;
5494
5495 if ( IsSelection() && addToSelected )
5496 {
5497 wxRect rect[4];
5498 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5499 int i;
5500
5501 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5502 wxCoord oldTop = m_selectedTopLeft.GetRow();
5503 wxCoord oldRight = m_selectedBottomRight.GetCol();
5504 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5505
5506 if ( oldTop > row )
5507 {
5508 need_refresh[0] = TRUE;
5509 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
5510 wxGridCellCoords ( oldTop - 1,
5511 m_numCols - 1 ) );
5512 m_selectedTopLeft.SetRow( row );
5513 }
5514
5515 if ( oldLeft > 0 )
5516 {
5517 need_refresh[1] = TRUE;
5518 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
5519 wxGridCellCoords ( oldBottom,
5520 oldLeft - 1 ) );
5521
5522 m_selectedTopLeft.SetCol( 0 );
5523 }
5524
5525 if ( oldBottom < row )
5526 {
5527 need_refresh[2] = TRUE;
5528 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
5529 wxGridCellCoords ( row,
5530 m_numCols - 1 ) );
5531 m_selectedBottomRight.SetRow( row );
5532 }
5533
5534 if ( oldRight < m_numCols - 1 )
5535 {
5536 need_refresh[3] = TRUE;
5537 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
5538 oldRight + 1 ),
5539 wxGridCellCoords ( oldBottom,
5540 m_numCols - 1 ) );
5541 m_selectedBottomRight.SetCol( m_numCols - 1 );
5542 }
5543
5544 for (i = 0; i < 4; i++ )
5545 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5546 m_gridWin->Refresh( FALSE, &(rect[i]) );
5547 }
5548 else
5549 {
5550 r = SelectionToDeviceRect();
5551 ClearSelection();
5552 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
5553
5554 m_selectedTopLeft.Set( row, 0 );
5555 m_selectedBottomRight.Set( row, m_numCols-1 );
5556 r = SelectionToDeviceRect();
5557 m_gridWin->Refresh( FALSE, &r );
5558 }
5559
5560 wxGridRangeSelectEvent gridEvt( GetId(),
5561 EVT_GRID_RANGE_SELECT,
5562 this,
5563 m_selectedTopLeft,
5564 m_selectedBottomRight );
5565
5566 GetEventHandler()->ProcessEvent(gridEvt);
5567 }
5568
5569
5570 void wxGrid::SelectCol( int col, bool addToSelected )
5571 {
5572 if ( IsSelection() && addToSelected )
5573 {
5574 wxRect rect[4];
5575 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5576 int i;
5577
5578 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5579 wxCoord oldTop = m_selectedTopLeft.GetRow();
5580 wxCoord oldRight = m_selectedBottomRight.GetCol();
5581 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5582
5583 if ( oldLeft > col )
5584 {
5585 need_refresh[0] = TRUE;
5586 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
5587 wxGridCellCoords ( m_numRows - 1,
5588 oldLeft - 1 ) );
5589 m_selectedTopLeft.SetCol( col );
5590 }
5591
5592 if ( oldTop > 0 )
5593 {
5594 need_refresh[1] = TRUE;
5595 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
5596 wxGridCellCoords ( oldTop - 1,
5597 oldRight ) );
5598 m_selectedTopLeft.SetRow( 0 );
5599 }
5600
5601 if ( oldRight < col )
5602 {
5603 need_refresh[2] = TRUE;
5604 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
5605 wxGridCellCoords ( m_numRows - 1,
5606 col ) );
5607 m_selectedBottomRight.SetCol( col );
5608 }
5609
5610 if ( oldBottom < m_numRows - 1 )
5611 {
5612 need_refresh[3] = TRUE;
5613 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
5614 oldLeft ),
5615 wxGridCellCoords ( m_numRows - 1,
5616 oldRight ) );
5617 m_selectedBottomRight.SetRow( m_numRows - 1 );
5618 }
5619
5620 for (i = 0; i < 4; i++ )
5621 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5622 m_gridWin->Refresh( FALSE, &(rect[i]) );
5623 }
5624 else
5625 {
5626 wxRect r;
5627
5628 r = SelectionToDeviceRect();
5629 ClearSelection();
5630 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
5631
5632 m_selectedTopLeft.Set( 0, col );
5633 m_selectedBottomRight.Set( m_numRows-1, col );
5634 r = SelectionToDeviceRect();
5635 m_gridWin->Refresh( FALSE, &r );
5636 }
5637
5638 wxGridRangeSelectEvent gridEvt( GetId(),
5639 EVT_GRID_RANGE_SELECT,
5640 this,
5641 m_selectedTopLeft,
5642 m_selectedBottomRight );
5643
5644 GetEventHandler()->ProcessEvent(gridEvt);
5645 }
5646
5647
5648 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
5649 {
5650 int temp;
5651 wxGridCellCoords updateTopLeft, updateBottomRight;
5652
5653 if ( topRow > bottomRow )
5654 {
5655 temp = topRow;
5656 topRow = bottomRow;
5657 bottomRow = temp;
5658 }
5659
5660 if ( leftCol > rightCol )
5661 {
5662 temp = leftCol;
5663 leftCol = rightCol;
5664 rightCol = temp;
5665 }
5666
5667 updateTopLeft = wxGridCellCoords( topRow, leftCol );
5668 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
5669
5670 if ( m_selectedTopLeft != updateTopLeft ||
5671 m_selectedBottomRight != updateBottomRight )
5672 {
5673 // Compute two optimal update rectangles:
5674 // Either one rectangle is a real subset of the
5675 // other, or they are (almost) disjoint!
5676 wxRect rect[4];
5677 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5678 int i;
5679
5680 // Store intermediate values
5681 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5682 wxCoord oldTop = m_selectedTopLeft.GetRow();
5683 wxCoord oldRight = m_selectedBottomRight.GetCol();
5684 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5685
5686 // Determine the outer/inner coordinates.
5687 if (oldLeft > leftCol)
5688 {
5689 temp = oldLeft;
5690 oldLeft = leftCol;
5691 leftCol = temp;
5692 }
5693 if (oldTop > topRow )
5694 {
5695 temp = oldTop;
5696 oldTop = topRow;
5697 topRow = temp;
5698 }
5699 if (oldRight < rightCol )
5700 {
5701 temp = oldRight;
5702 oldRight = rightCol;
5703 rightCol = temp;
5704 }
5705 if (oldBottom < bottomRow)
5706 {
5707 temp = oldBottom;
5708 oldBottom = bottomRow;
5709 bottomRow = temp;
5710 }
5711
5712 // Now, either the stuff marked old is the outer
5713 // rectangle or we don't have a situation where one
5714 // is contained in the other.
5715
5716 if ( oldLeft < leftCol )
5717 {
5718 need_refresh[0] = TRUE;
5719 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5720 oldLeft ),
5721 wxGridCellCoords ( oldBottom,
5722 leftCol - 1 ) );
5723 }
5724
5725 if ( oldTop < topRow )
5726 {
5727 need_refresh[1] = TRUE;
5728 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5729 leftCol ),
5730 wxGridCellCoords ( topRow - 1,
5731 rightCol ) );
5732 }
5733
5734 if ( oldRight > rightCol )
5735 {
5736 need_refresh[2] = TRUE;
5737 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5738 rightCol + 1 ),
5739 wxGridCellCoords ( oldBottom,
5740 oldRight ) );
5741 }
5742
5743 if ( oldBottom > bottomRow )
5744 {
5745 need_refresh[3] = TRUE;
5746 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
5747 leftCol ),
5748 wxGridCellCoords ( oldBottom,
5749 rightCol ) );
5750 }
5751
5752
5753 // Change Selection
5754 m_selectedTopLeft = updateTopLeft;
5755 m_selectedBottomRight = updateBottomRight;
5756
5757 // various Refresh() calls
5758 for (i = 0; i < 4; i++ )
5759 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5760 m_gridWin->Refresh( FALSE, &(rect[i]) );
5761 }
5762
5763 // only generate an event if the block is not being selected by
5764 // dragging the mouse (in which case the event will be generated in
5765 // the mouse event handler)
5766 if ( !m_isDragging )
5767 {
5768 wxGridRangeSelectEvent gridEvt( GetId(),
5769 EVT_GRID_RANGE_SELECT,
5770 this,
5771 m_selectedTopLeft,
5772 m_selectedBottomRight );
5773
5774 GetEventHandler()->ProcessEvent(gridEvt);
5775 }
5776 }
5777
5778 void wxGrid::SelectAll()
5779 {
5780 m_selectedTopLeft.Set( 0, 0 );
5781 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
5782
5783 m_gridWin->Refresh();
5784 }
5785
5786
5787 void wxGrid::ClearSelection()
5788 {
5789 m_selectedTopLeft = wxGridNoCellCoords;
5790 m_selectedBottomRight = wxGridNoCellCoords;
5791 }
5792
5793
5794 // This function returns the rectangle that encloses the given block
5795 // in device coords clipped to the client size of the grid window.
5796 //
5797 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
5798 const wxGridCellCoords &bottomRight )
5799 {
5800 wxRect rect( wxGridNoCellRect );
5801 wxRect cellRect;
5802
5803 cellRect = CellToRect( topLeft );
5804 if ( cellRect != wxGridNoCellRect )
5805 {
5806 rect = cellRect;
5807 }
5808 else
5809 {
5810 rect = wxRect( 0, 0, 0, 0 );
5811 }
5812
5813 cellRect = CellToRect( bottomRight );
5814 if ( cellRect != wxGridNoCellRect )
5815 {
5816 rect += cellRect;
5817 }
5818 else
5819 {
5820 return wxGridNoCellRect;
5821 }
5822
5823 // convert to scrolled coords
5824 //
5825 int left, top, right, bottom;
5826 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
5827 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
5828
5829 int cw, ch;
5830 m_gridWin->GetClientSize( &cw, &ch );
5831
5832 rect.SetLeft( wxMax(0, left) );
5833 rect.SetTop( wxMax(0, top) );
5834 rect.SetRight( wxMin(cw, right) );
5835 rect.SetBottom( wxMin(ch, bottom) );
5836
5837 return rect;
5838 }
5839
5840
5841
5842 //
5843 // ------ Grid event classes
5844 //
5845
5846 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
5847
5848 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
5849 int row, int col, int x, int y,
5850 bool control, bool shift, bool alt, bool meta )
5851 : wxNotifyEvent( type, id )
5852 {
5853 m_row = row;
5854 m_col = col;
5855 m_x = x;
5856 m_y = y;
5857 m_control = control;
5858 m_shift = shift;
5859 m_alt = alt;
5860 m_meta = meta;
5861
5862 SetEventObject(obj);
5863 }
5864
5865
5866 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
5867
5868 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
5869 int rowOrCol, int x, int y,
5870 bool control, bool shift, bool alt, bool meta )
5871 : wxNotifyEvent( type, id )
5872 {
5873 m_rowOrCol = rowOrCol;
5874 m_x = x;
5875 m_y = y;
5876 m_control = control;
5877 m_shift = shift;
5878 m_alt = alt;
5879 m_meta = meta;
5880
5881 SetEventObject(obj);
5882 }
5883
5884
5885 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
5886
5887 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
5888 const wxGridCellCoords& topLeft,
5889 const wxGridCellCoords& bottomRight,
5890 bool control, bool shift, bool alt, bool meta )
5891 : wxNotifyEvent( type, id )
5892 {
5893 m_topLeft = topLeft;
5894 m_bottomRight = bottomRight;
5895 m_control = control;
5896 m_shift = shift;
5897 m_alt = alt;
5898 m_meta = meta;
5899
5900 SetEventObject(obj);
5901 }
5902
5903
5904 #endif // ifndef wxUSE_NEW_GRID
5905