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