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