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