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