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