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