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