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