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