]> git.saurik.com Git - wxWidgets.git/blob - src/generic/grid.cpp
fatal bug in wxSplitPath 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, but in other way
918 size.x += 1;
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 static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
1461
1462 wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
1463 wxGridCellAttr& WXUNUSED(attr),
1464 wxDC& WXUNUSED(dc),
1465 int WXUNUSED(row),
1466 int WXUNUSED(col))
1467 {
1468 // compute it only once (no locks for MT safeness in GUI thread...)
1469 if ( !ms_sizeCheckMark.x )
1470 {
1471 // get checkbox size
1472 wxCoord checkSize = 0;
1473 wxCheckBox *checkbox = new wxCheckBox(&grid, -1, wxEmptyString);
1474 wxSize size = checkbox->GetBestSize();
1475 checkSize = size.y + 2*wxGRID_CHECKMARK_MARGIN;
1476
1477 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
1478 #if defined(__WXGTK__) || defined(__WXMOTIF__)
1479 checkSize -= size.y / 2;
1480 #endif
1481
1482 delete checkbox;
1483
1484 ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
1485 }
1486
1487 return ms_sizeCheckMark;
1488 }
1489
1490 void wxGridCellBoolRenderer::Draw(wxGrid& grid,
1491 wxGridCellAttr& attr,
1492 wxDC& dc,
1493 const wxRect& rect,
1494 int row, int col,
1495 bool isSelected)
1496 {
1497 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
1498
1499 // draw a check mark in the centre (ignoring alignment - TODO)
1500 wxSize size = GetBestSize(grid, attr, dc, row, col);
1501
1502 // don't draw outside the cell
1503 wxCoord minSize = wxMin(rect.width, rect.height);
1504 if ( size.x >= minSize || size.y >= minSize )
1505 {
1506 // and even leave (at least) 1 pixel margin
1507 size.x = size.y = minSize - 2;
1508 }
1509
1510 // draw a border around checkmark
1511 wxRect rectBorder;
1512 rectBorder.x = rect.x + rect.width/2 - size.x/2;
1513 rectBorder.y = rect.y + rect.height/2 - size.y/2;
1514 rectBorder.width = size.x;
1515 rectBorder.height = size.y;
1516
1517 bool value;
1518 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
1519 value = grid.GetTable()->GetValueAsBool(row, col);
1520 else
1521 value = !!grid.GetTable()->GetValue(row, col);
1522
1523 if ( value )
1524 {
1525 wxRect rectMark = rectBorder;
1526 #ifdef __WXMSW__
1527 // MSW DrawCheckMark() is weird (and should probably be changed...)
1528 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN/2);
1529 rectMark.x++;
1530 rectMark.y++;
1531 #else // !MSW
1532 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
1533 #endif // MSW/!MSW
1534
1535 dc.SetTextForeground(attr.GetTextColour());
1536 dc.DrawCheckMark(rectMark);
1537 }
1538
1539 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1540 dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
1541 dc.DrawRectangle(rectBorder);
1542 }
1543
1544 // ----------------------------------------------------------------------------
1545 // wxGridCellAttr
1546 // ----------------------------------------------------------------------------
1547
1548 wxGridCellAttr *wxGridCellAttr::Clone() const
1549 {
1550 wxGridCellAttr *attr = new wxGridCellAttr;
1551 if ( HasTextColour() )
1552 attr->SetTextColour(GetTextColour());
1553 if ( HasBackgroundColour() )
1554 attr->SetBackgroundColour(GetBackgroundColour());
1555 if ( HasFont() )
1556 attr->SetFont(GetFont());
1557 if ( HasAlignment() )
1558 attr->SetAlignment(m_hAlign, m_vAlign);
1559
1560 if ( m_renderer )
1561 {
1562 attr->SetRenderer(m_renderer);
1563 m_renderer->IncRef();
1564 }
1565 if ( m_editor )
1566 {
1567 attr->SetEditor(m_editor);
1568 m_editor->IncRef();
1569 }
1570
1571 if ( IsReadOnly() )
1572 attr->SetReadOnly();
1573
1574 attr->SetDefAttr(m_defGridAttr);
1575
1576 return attr;
1577 }
1578
1579 const wxColour& wxGridCellAttr::GetTextColour() const
1580 {
1581 if (HasTextColour())
1582 {
1583 return m_colText;
1584 }
1585 else if (m_defGridAttr != this)
1586 {
1587 return m_defGridAttr->GetTextColour();
1588 }
1589 else
1590 {
1591 wxFAIL_MSG(wxT("Missing default cell attribute"));
1592 return wxNullColour;
1593 }
1594 }
1595
1596
1597 const wxColour& wxGridCellAttr::GetBackgroundColour() const
1598 {
1599 if (HasBackgroundColour())
1600 return m_colBack;
1601 else if (m_defGridAttr != this)
1602 return m_defGridAttr->GetBackgroundColour();
1603 else
1604 {
1605 wxFAIL_MSG(wxT("Missing default cell attribute"));
1606 return wxNullColour;
1607 }
1608 }
1609
1610
1611 const wxFont& wxGridCellAttr::GetFont() const
1612 {
1613 if (HasFont())
1614 return m_font;
1615 else if (m_defGridAttr != this)
1616 return m_defGridAttr->GetFont();
1617 else
1618 {
1619 wxFAIL_MSG(wxT("Missing default cell attribute"));
1620 return wxNullFont;
1621 }
1622 }
1623
1624
1625 void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
1626 {
1627 if (HasAlignment())
1628 {
1629 if ( hAlign ) *hAlign = m_hAlign;
1630 if ( vAlign ) *vAlign = m_vAlign;
1631 }
1632 else if (m_defGridAttr != this)
1633 m_defGridAttr->GetAlignment(hAlign, vAlign);
1634 else
1635 {
1636 wxFAIL_MSG(wxT("Missing default cell attribute"));
1637 }
1638 }
1639
1640
1641 // GetRenderer and GetEditor use a slightly different decision path about
1642 // which attribute to use. If a non-default attr object has one then it is
1643 // used, otherwise the default editor or renderer is fetched from the grid and
1644 // used. It should be the default for the data type of the cell. If it is
1645 // NULL (because the table has a type that the grid does not have in its
1646 // registry,) then the grid's default editor or renderer is used.
1647
1648 wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
1649 {
1650 wxGridCellRenderer* renderer = NULL;
1651
1652 if ( m_defGridAttr != this || grid == NULL )
1653 {
1654 renderer = m_renderer; // use local attribute
1655 if ( renderer )
1656 renderer->IncRef();
1657 }
1658
1659 if ( !renderer && grid ) // get renderer for the data type
1660 {
1661 // GetDefaultRendererForCell() will do IncRef() for us
1662 renderer = grid->GetDefaultRendererForCell(row, col);
1663 }
1664
1665 if ( !renderer )
1666 {
1667 // if we still don't have one then use the grid default
1668 // (no need for IncRef() here neither)
1669 renderer = m_defGridAttr->GetRenderer(NULL,0,0);
1670 }
1671
1672 if ( !renderer)
1673 {
1674 wxFAIL_MSG(wxT("Missing default cell attribute"));
1675 }
1676
1677 return renderer;
1678 }
1679
1680 wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
1681 {
1682 wxGridCellEditor* editor = NULL;
1683
1684 if ( m_defGridAttr != this || grid == NULL )
1685 {
1686 editor = m_editor; // use local attribute
1687 if ( editor )
1688 editor->IncRef();
1689 }
1690
1691 if ( !editor && grid ) // get renderer for the data type
1692 editor = grid->GetDefaultEditorForCell(row, col);
1693
1694 if ( !editor )
1695 // if we still don't have one then use the grid default
1696 editor = m_defGridAttr->GetEditor(NULL,0,0);
1697
1698 if ( !editor )
1699 {
1700 wxFAIL_MSG(wxT("Missing default cell attribute"));
1701 }
1702
1703 return editor;
1704 }
1705
1706 // ----------------------------------------------------------------------------
1707 // wxGridCellAttrData
1708 // ----------------------------------------------------------------------------
1709
1710 void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
1711 {
1712 int n = FindIndex(row, col);
1713 if ( n == wxNOT_FOUND )
1714 {
1715 // add the attribute
1716 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
1717 }
1718 else
1719 {
1720 if ( attr )
1721 {
1722 // change the attribute
1723 m_attrs[(size_t)n].attr = attr;
1724 }
1725 else
1726 {
1727 // remove this attribute
1728 m_attrs.RemoveAt((size_t)n);
1729 }
1730 }
1731 }
1732
1733 wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
1734 {
1735 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
1736
1737 int n = FindIndex(row, col);
1738 if ( n != wxNOT_FOUND )
1739 {
1740 attr = m_attrs[(size_t)n].attr;
1741 attr->IncRef();
1742 }
1743
1744 return attr;
1745 }
1746
1747 void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
1748 {
1749 size_t count = m_attrs.GetCount();
1750 for ( size_t n = 0; n < count; n++ )
1751 {
1752 wxGridCellCoords& coords = m_attrs[n].coords;
1753 wxCoord row = coords.GetRow();
1754 if ((size_t)row >= pos)
1755 {
1756 if (numRows > 0)
1757 {
1758 // If rows inserted, include row counter where necessary
1759 coords.SetRow(row + numRows);
1760 }
1761 else if (numRows < 0)
1762 {
1763 // If rows deleted ...
1764 if ((size_t)row >= pos - numRows)
1765 {
1766 // ...either decrement row counter (if row still exists)...
1767 coords.SetRow(row + numRows);
1768 }
1769 else
1770 {
1771 // ...or remove the attribute
1772 m_attrs.RemoveAt((size_t)n);
1773 n--; count--;
1774 }
1775 }
1776 }
1777 }
1778 }
1779
1780 void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
1781 {
1782 size_t count = m_attrs.GetCount();
1783 for ( size_t n = 0; n < count; n++ )
1784 {
1785 wxGridCellCoords& coords = m_attrs[n].coords;
1786 wxCoord col = coords.GetCol();
1787 if ( (size_t)col >= pos )
1788 {
1789 if ( numCols > 0 )
1790 {
1791 // If rows inserted, include row counter where necessary
1792 coords.SetCol(col + numCols);
1793 }
1794 else if (numCols < 0)
1795 {
1796 // If rows deleted ...
1797 if ((size_t)col >= pos - numCols)
1798 {
1799 // ...either decrement row counter (if row still exists)...
1800 coords.SetCol(col + numCols);
1801 }
1802 else
1803 {
1804 // ...or remove the attribute
1805 m_attrs.RemoveAt((size_t)n);
1806 n--; count--;
1807 }
1808 }
1809 }
1810 }
1811 }
1812
1813 int wxGridCellAttrData::FindIndex(int row, int col) const
1814 {
1815 size_t count = m_attrs.GetCount();
1816 for ( size_t n = 0; n < count; n++ )
1817 {
1818 const wxGridCellCoords& coords = m_attrs[n].coords;
1819 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
1820 {
1821 return n;
1822 }
1823 }
1824
1825 return wxNOT_FOUND;
1826 }
1827
1828 // ----------------------------------------------------------------------------
1829 // wxGridRowOrColAttrData
1830 // ----------------------------------------------------------------------------
1831
1832 wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
1833 {
1834 size_t count = m_attrs.Count();
1835 for ( size_t n = 0; n < count; n++ )
1836 {
1837 m_attrs[n]->DecRef();
1838 }
1839 }
1840
1841 wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
1842 {
1843 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
1844
1845 int n = m_rowsOrCols.Index(rowOrCol);
1846 if ( n != wxNOT_FOUND )
1847 {
1848 attr = m_attrs[(size_t)n];
1849 attr->IncRef();
1850 }
1851
1852 return attr;
1853 }
1854
1855 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
1856 {
1857 int i = m_rowsOrCols.Index(rowOrCol);
1858 if ( i == wxNOT_FOUND )
1859 {
1860 // add the attribute
1861 m_rowsOrCols.Add(rowOrCol);
1862 m_attrs.Add(attr);
1863 }
1864 else
1865 {
1866 size_t n = (size_t)i;
1867 if ( attr )
1868 {
1869 // change the attribute
1870 m_attrs[n]->DecRef();
1871 m_attrs[n] = attr;
1872 }
1873 else
1874 {
1875 // remove this attribute
1876 m_attrs[n]->DecRef();
1877 m_rowsOrCols.RemoveAt(n);
1878 m_attrs.RemoveAt(n);
1879 }
1880 }
1881 }
1882
1883 void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
1884 {
1885 size_t count = m_attrs.GetCount();
1886 for ( size_t n = 0; n < count; n++ )
1887 {
1888 int & rowOrCol = m_rowsOrCols[n];
1889 if ( (size_t)rowOrCol >= pos )
1890 {
1891 if ( numRowsOrCols > 0 )
1892 {
1893 // If rows inserted, include row counter where necessary
1894 rowOrCol += numRowsOrCols;
1895 }
1896 else if ( numRowsOrCols < 0)
1897 {
1898 // If rows deleted, either decrement row counter (if row still exists)
1899 if ((size_t)rowOrCol >= pos - numRowsOrCols)
1900 rowOrCol += numRowsOrCols;
1901 else
1902 {
1903 m_rowsOrCols.RemoveAt((size_t)n);
1904 m_attrs.RemoveAt((size_t)n);
1905 n--; count--;
1906 }
1907 }
1908 }
1909 }
1910 }
1911
1912 // ----------------------------------------------------------------------------
1913 // wxGridCellAttrProvider
1914 // ----------------------------------------------------------------------------
1915
1916 wxGridCellAttrProvider::wxGridCellAttrProvider()
1917 {
1918 m_data = (wxGridCellAttrProviderData *)NULL;
1919 }
1920
1921 wxGridCellAttrProvider::~wxGridCellAttrProvider()
1922 {
1923 delete m_data;
1924 }
1925
1926 void wxGridCellAttrProvider::InitData()
1927 {
1928 m_data = new wxGridCellAttrProviderData;
1929 }
1930
1931 wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col) const
1932 {
1933 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
1934 if ( m_data )
1935 {
1936 // first look for the attribute of this specific cell
1937 attr = m_data->m_cellAttrs.GetAttr(row, col);
1938
1939 if ( !attr )
1940 {
1941 // then look for the col attr (col attributes are more common than
1942 // the row ones, hence they have priority)
1943 attr = m_data->m_colAttrs.GetAttr(col);
1944 }
1945
1946 if ( !attr )
1947 {
1948 // finally try the row attributes
1949 attr = m_data->m_rowAttrs.GetAttr(row);
1950 }
1951 }
1952
1953 return attr;
1954 }
1955
1956 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
1957 int row, int col)
1958 {
1959 if ( !m_data )
1960 InitData();
1961
1962 m_data->m_cellAttrs.SetAttr(attr, row, col);
1963 }
1964
1965 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
1966 {
1967 if ( !m_data )
1968 InitData();
1969
1970 m_data->m_rowAttrs.SetAttr(attr, row);
1971 }
1972
1973 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
1974 {
1975 if ( !m_data )
1976 InitData();
1977
1978 m_data->m_colAttrs.SetAttr(attr, col);
1979 }
1980
1981 void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
1982 {
1983 if ( m_data )
1984 {
1985 m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
1986
1987 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
1988 }
1989 }
1990
1991 void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
1992 {
1993 if ( m_data )
1994 {
1995 m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
1996
1997 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
1998 }
1999 }
2000
2001 // ----------------------------------------------------------------------------
2002 // wxGridTypeRegistry
2003 // ----------------------------------------------------------------------------
2004
2005 wxGridTypeRegistry::~wxGridTypeRegistry()
2006 {
2007 size_t count = m_typeinfo.Count();
2008 for ( size_t i = 0; i < count; i++ )
2009 delete m_typeinfo[i];
2010 }
2011
2012
2013 void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
2014 wxGridCellRenderer* renderer,
2015 wxGridCellEditor* editor)
2016 {
2017 wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
2018
2019 // is it already registered?
2020 int loc = FindRegisteredDataType(typeName);
2021 if ( loc != wxNOT_FOUND )
2022 {
2023 delete m_typeinfo[loc];
2024 m_typeinfo[loc] = info;
2025 }
2026 else
2027 {
2028 m_typeinfo.Add(info);
2029 }
2030 }
2031
2032 int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
2033 {
2034 size_t count = m_typeinfo.GetCount();
2035 for ( size_t i = 0; i < count; i++ )
2036 {
2037 if ( typeName == m_typeinfo[i]->m_typeName )
2038 {
2039 return i;
2040 }
2041 }
2042
2043 return wxNOT_FOUND;
2044 }
2045
2046 int wxGridTypeRegistry::FindDataType(const wxString& typeName)
2047 {
2048 int index = FindRegisteredDataType(typeName);
2049 if ( index == wxNOT_FOUND )
2050 {
2051 // check whether this is one of the standard ones, in which case
2052 // register it "on the fly"
2053 if ( typeName == wxGRID_VALUE_STRING )
2054 {
2055 RegisterDataType(wxGRID_VALUE_STRING,
2056 new wxGridCellStringRenderer,
2057 new wxGridCellTextEditor);
2058 }
2059 else if ( typeName == wxGRID_VALUE_BOOL )
2060 {
2061 RegisterDataType(wxGRID_VALUE_BOOL,
2062 new wxGridCellBoolRenderer,
2063 new wxGridCellBoolEditor);
2064 }
2065 else if ( typeName == wxGRID_VALUE_NUMBER )
2066 {
2067 RegisterDataType(wxGRID_VALUE_NUMBER,
2068 new wxGridCellNumberRenderer,
2069 new wxGridCellNumberEditor);
2070 }
2071 else if ( typeName == wxGRID_VALUE_FLOAT )
2072 {
2073 RegisterDataType(wxGRID_VALUE_FLOAT,
2074 new wxGridCellFloatRenderer,
2075 new wxGridCellFloatEditor);
2076 }
2077 else if ( typeName == wxGRID_VALUE_CHOICE )
2078 {
2079 RegisterDataType(wxGRID_VALUE_CHOICE,
2080 new wxGridCellStringRenderer,
2081 new wxGridCellChoiceEditor);
2082 }
2083 else
2084 {
2085 return wxNOT_FOUND;
2086 }
2087
2088 // we get here only if just added the entry for this type, so return
2089 // the last index
2090 index = m_typeinfo.GetCount() - 1;
2091 }
2092
2093 return index;
2094 }
2095
2096 int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
2097 {
2098 int index = FindDataType(typeName);
2099 if ( index == wxNOT_FOUND )
2100 {
2101 // the first part of the typename is the "real" type, anything after ':'
2102 // are the parameters for the renderer
2103 index = FindDataType(typeName.BeforeFirst(_T(':')));
2104 if ( index == wxNOT_FOUND )
2105 {
2106 return wxNOT_FOUND;
2107 }
2108
2109 wxGridCellRenderer *renderer = GetRenderer(index);
2110 wxGridCellRenderer *rendererOld = renderer;
2111 renderer = renderer->Clone();
2112 rendererOld->DecRef();
2113
2114 wxGridCellEditor *editor = GetEditor(index);
2115 wxGridCellEditor *editorOld = editor;
2116 editor = editor->Clone();
2117 editorOld->DecRef();
2118
2119 // do it even if there are no parameters to reset them to defaults
2120 wxString params = typeName.AfterFirst(_T(':'));
2121 renderer->SetParameters(params);
2122 editor->SetParameters(params);
2123
2124 // register the new typename
2125 RegisterDataType(typeName, renderer, editor);
2126
2127 // we just registered it, it's the last one
2128 index = m_typeinfo.GetCount() - 1;
2129 }
2130
2131 return index;
2132 }
2133
2134 wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
2135 {
2136 wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
2137 renderer->IncRef();
2138 return renderer;
2139 }
2140
2141 wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
2142 {
2143 wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
2144 editor->IncRef();
2145 return editor;
2146 }
2147
2148 // ----------------------------------------------------------------------------
2149 // wxGridTableBase
2150 // ----------------------------------------------------------------------------
2151
2152 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
2153
2154
2155 wxGridTableBase::wxGridTableBase()
2156 {
2157 m_view = (wxGrid *) NULL;
2158 m_attrProvider = (wxGridCellAttrProvider *) NULL;
2159 }
2160
2161 wxGridTableBase::~wxGridTableBase()
2162 {
2163 delete m_attrProvider;
2164 }
2165
2166 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
2167 {
2168 delete m_attrProvider;
2169 m_attrProvider = attrProvider;
2170 }
2171
2172 bool wxGridTableBase::CanHaveAttributes()
2173 {
2174 if ( ! GetAttrProvider() )
2175 {
2176 // use the default attr provider by default
2177 SetAttrProvider(new wxGridCellAttrProvider);
2178 }
2179 return TRUE;
2180 }
2181
2182 wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col)
2183 {
2184 if ( m_attrProvider )
2185 return m_attrProvider->GetAttr(row, col);
2186 else
2187 return (wxGridCellAttr *)NULL;
2188 }
2189
2190 void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
2191 {
2192 if ( m_attrProvider )
2193 {
2194 m_attrProvider->SetAttr(attr, row, col);
2195 }
2196 else
2197 {
2198 // as we take ownership of the pointer and don't store it, we must
2199 // free it now
2200 wxSafeDecRef(attr);
2201 }
2202 }
2203
2204 void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
2205 {
2206 if ( m_attrProvider )
2207 {
2208 m_attrProvider->SetRowAttr(attr, row);
2209 }
2210 else
2211 {
2212 // as we take ownership of the pointer and don't store it, we must
2213 // free it now
2214 wxSafeDecRef(attr);
2215 }
2216 }
2217
2218 void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
2219 {
2220 if ( m_attrProvider )
2221 {
2222 m_attrProvider->SetColAttr(attr, col);
2223 }
2224 else
2225 {
2226 // as we take ownership of the pointer and don't store it, we must
2227 // free it now
2228 wxSafeDecRef(attr);
2229 }
2230 }
2231
2232 void wxGridTableBase::UpdateAttrRows( size_t pos, int numRows )
2233 {
2234 if ( m_attrProvider )
2235 {
2236 m_attrProvider->UpdateAttrRows( pos, numRows );
2237 }
2238 }
2239
2240 void wxGridTableBase::UpdateAttrCols( size_t pos, int numCols )
2241 {
2242 if ( m_attrProvider )
2243 {
2244 m_attrProvider->UpdateAttrCols( pos, numCols );
2245 }
2246 }
2247
2248 bool wxGridTableBase::InsertRows( size_t pos, size_t numRows )
2249 {
2250 wxFAIL_MSG( wxT("Called grid table class function InsertRows\n"
2251 "but your derived table class does not override this function") );
2252
2253 return FALSE;
2254 }
2255
2256 bool wxGridTableBase::AppendRows( size_t numRows )
2257 {
2258 wxFAIL_MSG( wxT("Called grid table class function AppendRows\n"
2259 "but your derived table class does not override this function"));
2260
2261 return FALSE;
2262 }
2263
2264 bool wxGridTableBase::DeleteRows( size_t pos, size_t numRows )
2265 {
2266 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\n"
2267 "but your derived table class does not override this function"));
2268
2269 return FALSE;
2270 }
2271
2272 bool wxGridTableBase::InsertCols( size_t pos, size_t numCols )
2273 {
2274 wxFAIL_MSG( wxT("Called grid table class function InsertCols\n"
2275 "but your derived table class does not override this function"));
2276
2277 return FALSE;
2278 }
2279
2280 bool wxGridTableBase::AppendCols( size_t numCols )
2281 {
2282 wxFAIL_MSG(wxT("Called grid table class function AppendCols\n"
2283 "but your derived table class does not override this function"));
2284
2285 return FALSE;
2286 }
2287
2288 bool wxGridTableBase::DeleteCols( size_t pos, size_t numCols )
2289 {
2290 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\n"
2291 "but your derived table class does not override this function"));
2292
2293 return FALSE;
2294 }
2295
2296
2297 wxString wxGridTableBase::GetRowLabelValue( int row )
2298 {
2299 wxString s;
2300 s << row + 1; // RD: Starting the rows at zero confuses users, no matter
2301 // how much it makes sense to us geeks.
2302 return s;
2303 }
2304
2305 wxString wxGridTableBase::GetColLabelValue( int col )
2306 {
2307 // default col labels are:
2308 // cols 0 to 25 : A-Z
2309 // cols 26 to 675 : AA-ZZ
2310 // etc.
2311
2312 wxString s;
2313 unsigned int i, n;
2314 for ( n = 1; ; n++ )
2315 {
2316 s += (_T('A') + (wxChar)( col%26 ));
2317 col = col/26 - 1;
2318 if ( col < 0 ) break;
2319 }
2320
2321 // reverse the string...
2322 wxString s2;
2323 for ( i = 0; i < n; i++ )
2324 {
2325 s2 += s[n-i-1];
2326 }
2327
2328 return s2;
2329 }
2330
2331
2332 wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
2333 {
2334 return wxGRID_VALUE_STRING;
2335 }
2336
2337 bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
2338 const wxString& typeName )
2339 {
2340 return typeName == wxGRID_VALUE_STRING;
2341 }
2342
2343 bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
2344 {
2345 return CanGetValueAs(row, col, typeName);
2346 }
2347
2348 long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
2349 {
2350 return 0;
2351 }
2352
2353 double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
2354 {
2355 return 0.0;
2356 }
2357
2358 bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
2359 {
2360 return FALSE;
2361 }
2362
2363 void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
2364 long WXUNUSED(value) )
2365 {
2366 }
2367
2368 void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
2369 double WXUNUSED(value) )
2370 {
2371 }
2372
2373 void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
2374 bool WXUNUSED(value) )
2375 {
2376 }
2377
2378
2379 void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
2380 const wxString& WXUNUSED(typeName) )
2381 {
2382 return NULL;
2383 }
2384
2385 void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
2386 const wxString& WXUNUSED(typeName),
2387 void* WXUNUSED(value) )
2388 {
2389 }
2390
2391 //////////////////////////////////////////////////////////////////////
2392 //
2393 // Message class for the grid table to send requests and notifications
2394 // to the grid view
2395 //
2396
2397 wxGridTableMessage::wxGridTableMessage()
2398 {
2399 m_table = (wxGridTableBase *) NULL;
2400 m_id = -1;
2401 m_comInt1 = -1;
2402 m_comInt2 = -1;
2403 }
2404
2405 wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
2406 int commandInt1, int commandInt2 )
2407 {
2408 m_table = table;
2409 m_id = id;
2410 m_comInt1 = commandInt1;
2411 m_comInt2 = commandInt2;
2412 }
2413
2414
2415
2416 //////////////////////////////////////////////////////////////////////
2417 //
2418 // A basic grid table for string data. An object of this class will
2419 // created by wxGrid if you don't specify an alternative table class.
2420 //
2421
2422 WX_DEFINE_OBJARRAY(wxGridStringArray)
2423
2424 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
2425
2426 wxGridStringTable::wxGridStringTable()
2427 : wxGridTableBase()
2428 {
2429 }
2430
2431 wxGridStringTable::wxGridStringTable( int numRows, int numCols )
2432 : wxGridTableBase()
2433 {
2434 int row, col;
2435
2436 m_data.Alloc( numRows );
2437
2438 wxArrayString sa;
2439 sa.Alloc( numCols );
2440 for ( col = 0; col < numCols; col++ )
2441 {
2442 sa.Add( wxEmptyString );
2443 }
2444
2445 for ( row = 0; row < numRows; row++ )
2446 {
2447 m_data.Add( sa );
2448 }
2449 }
2450
2451 wxGridStringTable::~wxGridStringTable()
2452 {
2453 }
2454
2455 long wxGridStringTable::GetNumberRows()
2456 {
2457 return m_data.GetCount();
2458 }
2459
2460 long wxGridStringTable::GetNumberCols()
2461 {
2462 if ( m_data.GetCount() > 0 )
2463 return m_data[0].GetCount();
2464 else
2465 return 0;
2466 }
2467
2468 wxString wxGridStringTable::GetValue( int row, int col )
2469 {
2470 wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
2471 _T("invalid row or column index in wxGridStringTable") );
2472
2473 return m_data[row][col];
2474 }
2475
2476 void wxGridStringTable::SetValue( int row, int col, const wxString& value )
2477 {
2478 wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
2479 _T("invalid row or column index in wxGridStringTable") );
2480
2481 m_data[row][col] = value;
2482 }
2483
2484 bool wxGridStringTable::IsEmptyCell( int row, int col )
2485 {
2486 wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
2487 _T("invalid row or column index in wxGridStringTable") );
2488
2489 return (m_data[row][col] == wxEmptyString);
2490 }
2491
2492 void wxGridStringTable::Clear()
2493 {
2494 int row, col;
2495 int numRows, numCols;
2496
2497 numRows = m_data.GetCount();
2498 if ( numRows > 0 )
2499 {
2500 numCols = m_data[0].GetCount();
2501
2502 for ( row = 0; row < numRows; row++ )
2503 {
2504 for ( col = 0; col < numCols; col++ )
2505 {
2506 m_data[row][col] = wxEmptyString;
2507 }
2508 }
2509 }
2510 }
2511
2512
2513 bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
2514 {
2515 size_t row, col;
2516
2517 size_t curNumRows = m_data.GetCount();
2518 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
2519
2520 if ( pos >= curNumRows )
2521 {
2522 return AppendRows( numRows );
2523 }
2524
2525 wxArrayString sa;
2526 sa.Alloc( curNumCols );
2527 for ( col = 0; col < curNumCols; col++ )
2528 {
2529 sa.Add( wxEmptyString );
2530 }
2531
2532 for ( row = pos; row < pos + numRows; row++ )
2533 {
2534 m_data.Insert( sa, row );
2535 }
2536 UpdateAttrRows( pos, numRows );
2537 if ( GetView() )
2538 {
2539 wxGridTableMessage msg( this,
2540 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
2541 pos,
2542 numRows );
2543
2544 GetView()->ProcessTableMessage( msg );
2545 }
2546
2547 return TRUE;
2548 }
2549
2550 bool wxGridStringTable::AppendRows( size_t numRows )
2551 {
2552 size_t row, col;
2553
2554 size_t curNumRows = m_data.GetCount();
2555 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
2556
2557 wxArrayString sa;
2558 if ( curNumCols > 0 )
2559 {
2560 sa.Alloc( curNumCols );
2561 for ( col = 0; col < curNumCols; col++ )
2562 {
2563 sa.Add( wxEmptyString );
2564 }
2565 }
2566
2567 for ( row = 0; row < numRows; row++ )
2568 {
2569 m_data.Add( sa );
2570 }
2571
2572 if ( GetView() )
2573 {
2574 wxGridTableMessage msg( this,
2575 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
2576 numRows );
2577
2578 GetView()->ProcessTableMessage( msg );
2579 }
2580
2581 return TRUE;
2582 }
2583
2584 bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
2585 {
2586 size_t n;
2587
2588 size_t curNumRows = m_data.GetCount();
2589
2590 if ( pos >= curNumRows )
2591 {
2592 wxString errmsg;
2593 errmsg.Printf("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\n"
2594 "Pos value is invalid for present table with %d rows",
2595 pos, numRows, curNumRows );
2596 wxFAIL_MSG( wxT(errmsg) );
2597 return FALSE;
2598 }
2599
2600 if ( numRows > curNumRows - pos )
2601 {
2602 numRows = curNumRows - pos;
2603 }
2604
2605 if ( numRows >= curNumRows )
2606 {
2607 m_data.Empty(); // don't release memory just yet
2608 }
2609 else
2610 {
2611 for ( n = 0; n < numRows; n++ )
2612 {
2613 m_data.Remove( pos );
2614 }
2615 }
2616 UpdateAttrRows( pos, -((int)numRows) );
2617 if ( GetView() )
2618 {
2619 wxGridTableMessage msg( this,
2620 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
2621 pos,
2622 numRows );
2623
2624 GetView()->ProcessTableMessage( msg );
2625 }
2626
2627 return TRUE;
2628 }
2629
2630 bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
2631 {
2632 size_t row, col;
2633
2634 size_t curNumRows = m_data.GetCount();
2635 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
2636
2637 if ( pos >= curNumCols )
2638 {
2639 return AppendCols( numCols );
2640 }
2641
2642 for ( row = 0; row < curNumRows; row++ )
2643 {
2644 for ( col = pos; col < pos + numCols; col++ )
2645 {
2646 m_data[row].Insert( wxEmptyString, col );
2647 }
2648 }
2649 UpdateAttrCols( pos, numCols );
2650 if ( GetView() )
2651 {
2652 wxGridTableMessage msg( this,
2653 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
2654 pos,
2655 numCols );
2656
2657 GetView()->ProcessTableMessage( msg );
2658 }
2659
2660 return TRUE;
2661 }
2662
2663 bool wxGridStringTable::AppendCols( size_t numCols )
2664 {
2665 size_t row, n;
2666
2667 size_t curNumRows = m_data.GetCount();
2668 if ( !curNumRows )
2669 {
2670 // TODO: something better than this ?
2671 //
2672 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\n"
2673 "Call AppendRows() first") );
2674 return FALSE;
2675 }
2676
2677 for ( row = 0; row < curNumRows; row++ )
2678 {
2679 for ( n = 0; n < numCols; n++ )
2680 {
2681 m_data[row].Add( wxEmptyString );
2682 }
2683 }
2684
2685 if ( GetView() )
2686 {
2687 wxGridTableMessage msg( this,
2688 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
2689 numCols );
2690
2691 GetView()->ProcessTableMessage( msg );
2692 }
2693
2694 return TRUE;
2695 }
2696
2697 bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
2698 {
2699 size_t row, n;
2700
2701 size_t curNumRows = m_data.GetCount();
2702 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
2703
2704 if ( pos >= curNumCols )
2705 {
2706 wxString errmsg;
2707 errmsg.Printf( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
2708 "Pos value is invalid for present table with %d cols",
2709 pos, numCols, curNumCols );
2710 wxFAIL_MSG( wxT( errmsg ) );
2711 return FALSE;
2712 }
2713
2714 if ( numCols > curNumCols - pos )
2715 {
2716 numCols = curNumCols - pos;
2717 }
2718
2719 for ( row = 0; row < curNumRows; row++ )
2720 {
2721 if ( numCols >= curNumCols )
2722 {
2723 m_data[row].Clear();
2724 }
2725 else
2726 {
2727 for ( n = 0; n < numCols; n++ )
2728 {
2729 m_data[row].Remove( pos );
2730 }
2731 }
2732 }
2733 UpdateAttrCols( pos, -((int)numCols) );
2734 if ( GetView() )
2735 {
2736 wxGridTableMessage msg( this,
2737 wxGRIDTABLE_NOTIFY_COLS_DELETED,
2738 pos,
2739 numCols );
2740
2741 GetView()->ProcessTableMessage( msg );
2742 }
2743
2744 return TRUE;
2745 }
2746
2747 wxString wxGridStringTable::GetRowLabelValue( int row )
2748 {
2749 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
2750 {
2751 // using default label
2752 //
2753 return wxGridTableBase::GetRowLabelValue( row );
2754 }
2755 else
2756 {
2757 return m_rowLabels[ row ];
2758 }
2759 }
2760
2761 wxString wxGridStringTable::GetColLabelValue( int col )
2762 {
2763 if ( col > (int)(m_colLabels.GetCount()) - 1 )
2764 {
2765 // using default label
2766 //
2767 return wxGridTableBase::GetColLabelValue( col );
2768 }
2769 else
2770 {
2771 return m_colLabels[ col ];
2772 }
2773 }
2774
2775 void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
2776 {
2777 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
2778 {
2779 int n = m_rowLabels.GetCount();
2780 int i;
2781 for ( i = n; i <= row; i++ )
2782 {
2783 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
2784 }
2785 }
2786
2787 m_rowLabels[row] = value;
2788 }
2789
2790 void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
2791 {
2792 if ( col > (int)(m_colLabels.GetCount()) - 1 )
2793 {
2794 int n = m_colLabels.GetCount();
2795 int i;
2796 for ( i = n; i <= col; i++ )
2797 {
2798 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
2799 }
2800 }
2801
2802 m_colLabels[col] = value;
2803 }
2804
2805
2806
2807 //////////////////////////////////////////////////////////////////////
2808 //////////////////////////////////////////////////////////////////////
2809
2810 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
2811
2812 BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
2813 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
2814 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
2815 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
2816 END_EVENT_TABLE()
2817
2818 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
2819 wxWindowID id,
2820 const wxPoint &pos, const wxSize &size )
2821 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
2822 {
2823 m_owner = parent;
2824 }
2825
2826 void wxGridRowLabelWindow::OnPaint( wxPaintEvent &event )
2827 {
2828 wxPaintDC dc(this);
2829
2830 // NO - don't do this because it will set both the x and y origin
2831 // coords to match the parent scrolled window and we just want to
2832 // set the y coord - MB
2833 //
2834 // m_owner->PrepareDC( dc );
2835
2836 int x, y;
2837 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
2838 dc.SetDeviceOrigin( 0, -y );
2839
2840 m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
2841 m_owner->DrawRowLabels( dc );
2842 }
2843
2844
2845 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
2846 {
2847 m_owner->ProcessRowLabelMouseEvent( event );
2848 }
2849
2850
2851 // This seems to be required for wxMotif otherwise the mouse
2852 // cursor must be in the cell edit control to get key events
2853 //
2854 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
2855 {
2856 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
2857 }
2858
2859
2860
2861 //////////////////////////////////////////////////////////////////////
2862
2863 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
2864
2865 BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
2866 EVT_PAINT( wxGridColLabelWindow::OnPaint )
2867 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
2868 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
2869 END_EVENT_TABLE()
2870
2871 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
2872 wxWindowID id,
2873 const wxPoint &pos, const wxSize &size )
2874 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
2875 {
2876 m_owner = parent;
2877 }
2878
2879 void wxGridColLabelWindow::OnPaint( wxPaintEvent &event )
2880 {
2881 wxPaintDC dc(this);
2882
2883 // NO - don't do this because it will set both the x and y origin
2884 // coords to match the parent scrolled window and we just want to
2885 // set the x coord - MB
2886 //
2887 // m_owner->PrepareDC( dc );
2888
2889 int x, y;
2890 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
2891 dc.SetDeviceOrigin( -x, 0 );
2892
2893 m_owner->CalcColLabelsExposed( GetUpdateRegion() );
2894 m_owner->DrawColLabels( dc );
2895 }
2896
2897
2898 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
2899 {
2900 m_owner->ProcessColLabelMouseEvent( event );
2901 }
2902
2903
2904 // This seems to be required for wxMotif otherwise the mouse
2905 // cursor must be in the cell edit control to get key events
2906 //
2907 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
2908 {
2909 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
2910 }
2911
2912
2913
2914 //////////////////////////////////////////////////////////////////////
2915
2916 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
2917
2918 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
2919 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
2920 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
2921 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
2922 END_EVENT_TABLE()
2923
2924 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
2925 wxWindowID id,
2926 const wxPoint &pos, const wxSize &size )
2927 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
2928 {
2929 m_owner = parent;
2930 }
2931
2932 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
2933 {
2934 wxPaintDC dc(this);
2935
2936 int client_height = 0;
2937 int client_width = 0;
2938 GetClientSize( &client_width, &client_height );
2939
2940 dc.SetPen( *wxBLACK_PEN );
2941 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
2942 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
2943
2944 dc.SetPen( *wxWHITE_PEN );
2945 dc.DrawLine( 0, 0, client_width, 0 );
2946 dc.DrawLine( 0, 0, 0, client_height );
2947 }
2948
2949
2950 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
2951 {
2952 m_owner->ProcessCornerLabelMouseEvent( event );
2953 }
2954
2955
2956 // This seems to be required for wxMotif otherwise the mouse
2957 // cursor must be in the cell edit control to get key events
2958 //
2959 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
2960 {
2961 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
2962 }
2963
2964
2965
2966 //////////////////////////////////////////////////////////////////////
2967
2968 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
2969
2970 BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
2971 EVT_PAINT( wxGridWindow::OnPaint )
2972 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
2973 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
2974 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
2975 END_EVENT_TABLE()
2976
2977 wxGridWindow::wxGridWindow( wxGrid *parent,
2978 wxGridRowLabelWindow *rowLblWin,
2979 wxGridColLabelWindow *colLblWin,
2980 wxWindowID id, const wxPoint &pos, const wxSize &size )
2981 : wxPanel( parent, id, pos, size, wxWANTS_CHARS, "grid window" )
2982 {
2983 m_owner = parent;
2984 m_rowLabelWin = rowLblWin;
2985 m_colLabelWin = colLblWin;
2986 SetBackgroundColour( "WHITE" );
2987 }
2988
2989
2990 wxGridWindow::~wxGridWindow()
2991 {
2992 }
2993
2994
2995 void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
2996 {
2997 wxPaintDC dc( this );
2998 m_owner->PrepareDC( dc );
2999 wxRegion reg = GetUpdateRegion();
3000 m_owner->CalcCellsExposed( reg );
3001 m_owner->DrawGridCellArea( dc );
3002 #if WXGRID_DRAW_LINES
3003 m_owner->DrawAllGridLines( dc, reg );
3004 #endif
3005 m_owner->DrawGridSpace( dc );
3006 m_owner->DrawHighlight( dc );
3007 }
3008
3009
3010 void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
3011 {
3012 wxPanel::ScrollWindow( dx, dy, rect );
3013 m_rowLabelWin->ScrollWindow( 0, dy, rect );
3014 m_colLabelWin->ScrollWindow( dx, 0, rect );
3015 }
3016
3017
3018 void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
3019 {
3020 m_owner->ProcessGridCellMouseEvent( event );
3021 }
3022
3023
3024 // This seems to be required for wxMotif otherwise the mouse
3025 // cursor must be in the cell edit control to get key events
3026 //
3027 void wxGridWindow::OnKeyDown( wxKeyEvent& event )
3028 {
3029 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
3030 }
3031
3032
3033 void wxGridWindow::OnEraseBackground(wxEraseEvent& event)
3034 {
3035 }
3036
3037
3038 //////////////////////////////////////////////////////////////////////
3039
3040
3041 IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
3042
3043 BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
3044 EVT_PAINT( wxGrid::OnPaint )
3045 EVT_SIZE( wxGrid::OnSize )
3046 EVT_KEY_DOWN( wxGrid::OnKeyDown )
3047 EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground )
3048 END_EVENT_TABLE()
3049
3050 wxGrid::wxGrid( wxWindow *parent,
3051 wxWindowID id,
3052 const wxPoint& pos,
3053 const wxSize& size,
3054 long style,
3055 const wxString& name )
3056 : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ),
3057 m_colMinWidths(GRID_HASH_SIZE),
3058 m_rowMinHeights(GRID_HASH_SIZE)
3059 {
3060 Create();
3061 }
3062
3063
3064 wxGrid::~wxGrid()
3065 {
3066 ClearAttrCache();
3067 wxSafeDecRef(m_defaultCellAttr);
3068
3069 #ifdef DEBUG_ATTR_CACHE
3070 size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
3071 wxPrintf(_T("wxGrid attribute cache statistics: "
3072 "total: %u, hits: %u (%u%%)\n"),
3073 total, gs_nAttrCacheHits,
3074 total ? (gs_nAttrCacheHits*100) / total : 0);
3075 #endif
3076
3077 if (m_ownTable)
3078 delete m_table;
3079
3080 delete m_typeRegistry;
3081 }
3082
3083
3084 //
3085 // ----- internal init and update functions
3086 //
3087
3088 void wxGrid::Create()
3089 {
3090 m_created = FALSE; // set to TRUE by CreateGrid
3091 m_displayed = TRUE; // FALSE; // set to TRUE by OnPaint
3092
3093 m_table = (wxGridTableBase *) NULL;
3094 m_ownTable = FALSE;
3095
3096 m_cellEditCtrlEnabled = FALSE;
3097
3098 m_defaultCellAttr = new wxGridCellAttr;
3099 m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
3100
3101 // Set default cell attributes
3102 m_defaultCellAttr->SetFont(GetFont());
3103 m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP);
3104 m_defaultCellAttr->SetTextColour(
3105 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
3106 m_defaultCellAttr->SetBackgroundColour(
3107 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
3108 m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
3109 m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
3110
3111
3112 m_numRows = 0;
3113 m_numCols = 0;
3114 m_currentCellCoords = wxGridNoCellCoords;
3115
3116 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
3117 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
3118
3119 // create the type registry
3120 m_typeRegistry = new wxGridTypeRegistry;
3121
3122 // subwindow components that make up the wxGrid
3123 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
3124 -1,
3125 wxDefaultPosition,
3126 wxDefaultSize );
3127
3128 m_rowLabelWin = new wxGridRowLabelWindow( this,
3129 -1,
3130 wxDefaultPosition,
3131 wxDefaultSize );
3132
3133 m_colLabelWin = new wxGridColLabelWindow( this,
3134 -1,
3135 wxDefaultPosition,
3136 wxDefaultSize );
3137
3138 m_gridWin = new wxGridWindow( this,
3139 m_rowLabelWin,
3140 m_colLabelWin,
3141 -1,
3142 wxDefaultPosition,
3143 wxDefaultSize );
3144
3145 SetTargetWindow( m_gridWin );
3146 }
3147
3148
3149 bool wxGrid::CreateGrid( int numRows, int numCols )
3150 {
3151 if ( m_created )
3152 {
3153 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
3154 return FALSE;
3155 }
3156 else
3157 {
3158 m_numRows = numRows;
3159 m_numCols = numCols;
3160
3161 m_table = new wxGridStringTable( m_numRows, m_numCols );
3162 m_table->SetView( this );
3163 m_ownTable = TRUE;
3164 Init();
3165 m_created = TRUE;
3166 }
3167
3168 return m_created;
3169 }
3170
3171 bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership )
3172 {
3173 if ( m_created )
3174 {
3175 // RD: Actually, this should probably be allowed. I think it would be
3176 // nice to be able to switch multiple Tables in and out of a single
3177 // View at runtime. Is there anything in the implmentation that would
3178 // prevent this?
3179
3180 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
3181 return FALSE;
3182 }
3183 else
3184 {
3185 m_numRows = table->GetNumberRows();
3186 m_numCols = table->GetNumberCols();
3187
3188 m_table = table;
3189 m_table->SetView( this );
3190 if (takeOwnership)
3191 m_ownTable = TRUE;
3192 Init();
3193 m_created = TRUE;
3194 }
3195
3196 return m_created;
3197 }
3198
3199
3200 void wxGrid::Init()
3201 {
3202 if ( m_numRows <= 0 )
3203 m_numRows = WXGRID_DEFAULT_NUMBER_ROWS;
3204
3205 if ( m_numCols <= 0 )
3206 m_numCols = WXGRID_DEFAULT_NUMBER_COLS;
3207
3208 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
3209 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
3210
3211 if ( m_rowLabelWin )
3212 {
3213 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
3214 }
3215 else
3216 {
3217 m_labelBackgroundColour = wxColour( _T("WHITE") );
3218 }
3219
3220 m_labelTextColour = wxColour( _T("BLACK") );
3221
3222 // init attr cache
3223 m_attrCache.row = -1;
3224
3225 // TODO: something better than this ?
3226 //
3227 m_labelFont = this->GetFont();
3228 m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 );
3229
3230 m_rowLabelHorizAlign = wxLEFT;
3231 m_rowLabelVertAlign = wxCENTRE;
3232
3233 m_colLabelHorizAlign = wxCENTRE;
3234 m_colLabelVertAlign = wxTOP;
3235
3236 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
3237 m_defaultRowHeight = m_gridWin->GetCharHeight();
3238
3239 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
3240 m_defaultRowHeight += 8;
3241 #else
3242 m_defaultRowHeight += 4;
3243 #endif
3244
3245 m_gridLineColour = wxColour( 128, 128, 255 );
3246 m_gridLinesEnabled = TRUE;
3247
3248 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
3249 m_winCapture = (wxWindow *)NULL;
3250 m_canDragRowSize = TRUE;
3251 m_canDragColSize = TRUE;
3252 m_canDragGridSize = TRUE;
3253 m_dragLastPos = -1;
3254 m_dragRowOrCol = -1;
3255 m_isDragging = FALSE;
3256 m_startDragPos = wxDefaultPosition;
3257
3258 m_waitForSlowClick = FALSE;
3259
3260 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
3261 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
3262
3263 m_currentCellCoords = wxGridNoCellCoords;
3264
3265 m_selectedTopLeft = wxGridNoCellCoords;
3266 m_selectedBottomRight = wxGridNoCellCoords;
3267 m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT);
3268 m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
3269
3270 m_editable = TRUE; // default for whole grid
3271
3272 m_inOnKeyDown = FALSE;
3273 m_batchCount = 0;
3274
3275 m_extraWidth =
3276 m_extraHeight = 50;
3277
3278 CalcDimensions();
3279 }
3280
3281 // ----------------------------------------------------------------------------
3282 // the idea is to call these functions only when necessary because they create
3283 // quite big arrays which eat memory mostly unnecessary - in particular, if
3284 // default widths/heights are used for all rows/columns, we may not use these
3285 // arrays at all
3286 //
3287 // with some extra code, it should be possible to only store the
3288 // widths/heights different from default ones but this will be done later...
3289 // ----------------------------------------------------------------------------
3290
3291 void wxGrid::InitRowHeights()
3292 {
3293 m_rowHeights.Empty();
3294 m_rowBottoms.Empty();
3295
3296 m_rowHeights.Alloc( m_numRows );
3297 m_rowBottoms.Alloc( m_numRows );
3298
3299 int rowBottom = 0;
3300 for ( int i = 0; i < m_numRows; i++ )
3301 {
3302 m_rowHeights.Add( m_defaultRowHeight );
3303 rowBottom += m_defaultRowHeight;
3304 m_rowBottoms.Add( rowBottom );
3305 }
3306 }
3307
3308 void wxGrid::InitColWidths()
3309 {
3310 m_colWidths.Empty();
3311 m_colRights.Empty();
3312
3313 m_colWidths.Alloc( m_numCols );
3314 m_colRights.Alloc( m_numCols );
3315 int colRight = 0;
3316 for ( int i = 0; i < m_numCols; i++ )
3317 {
3318 m_colWidths.Add( m_defaultColWidth );
3319 colRight += m_defaultColWidth;
3320 m_colRights.Add( colRight );
3321 }
3322 }
3323
3324 int wxGrid::GetColWidth(int col) const
3325 {
3326 return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col];
3327 }
3328
3329 int wxGrid::GetColLeft(int col) const
3330 {
3331 return m_colRights.IsEmpty() ? col * m_defaultColWidth
3332 : m_colRights[col] - m_colWidths[col];
3333 }
3334
3335 int wxGrid::GetColRight(int col) const
3336 {
3337 return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth
3338 : m_colRights[col];
3339 }
3340
3341 int wxGrid::GetRowHeight(int row) const
3342 {
3343 return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row];
3344 }
3345
3346 int wxGrid::GetRowTop(int row) const
3347 {
3348 return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight
3349 : m_rowBottoms[row] - m_rowHeights[row];
3350 }
3351
3352 int wxGrid::GetRowBottom(int row) const
3353 {
3354 return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight
3355 : m_rowBottoms[row];
3356 }
3357
3358 void wxGrid::CalcDimensions()
3359 {
3360 int cw, ch;
3361 GetClientSize( &cw, &ch );
3362
3363 if ( m_numRows > 0 && m_numCols > 0 )
3364 {
3365 int right = GetColRight( m_numCols-1 ) + m_extraWidth;
3366 int bottom = GetRowBottom( m_numRows-1 ) + m_extraHeight;
3367
3368 // TODO: restore the scroll position that we had before sizing
3369 //
3370 int x, y;
3371 GetViewStart( &x, &y );
3372 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
3373 right/GRID_SCROLL_LINE, bottom/GRID_SCROLL_LINE,
3374 x, y );
3375 }
3376 }
3377
3378
3379 void wxGrid::CalcWindowSizes()
3380 {
3381 int cw, ch;
3382 GetClientSize( &cw, &ch );
3383
3384 if ( m_cornerLabelWin->IsShown() )
3385 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
3386
3387 if ( m_colLabelWin->IsShown() )
3388 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
3389
3390 if ( m_rowLabelWin->IsShown() )
3391 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
3392
3393 if ( m_gridWin->IsShown() )
3394 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
3395 }
3396
3397
3398 // this is called when the grid table sends a message to say that it
3399 // has been redimensioned
3400 //
3401 bool wxGrid::Redimension( wxGridTableMessage& msg )
3402 {
3403 int i;
3404
3405 // if we were using the default widths/heights so far, we must change them
3406 // now
3407 if ( m_colWidths.IsEmpty() )
3408 {
3409 InitColWidths();
3410 }
3411
3412 if ( m_rowHeights.IsEmpty() )
3413 {
3414 InitRowHeights();
3415 }
3416
3417 switch ( msg.GetId() )
3418 {
3419 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
3420 {
3421 size_t pos = msg.GetCommandInt();
3422 int numRows = msg.GetCommandInt2();
3423 for ( i = 0; i < numRows; i++ )
3424 {
3425 m_rowHeights.Insert( m_defaultRowHeight, pos );
3426 m_rowBottoms.Insert( 0, pos );
3427 }
3428 m_numRows += numRows;
3429
3430 int bottom = 0;
3431 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
3432
3433 for ( i = pos; i < m_numRows; i++ )
3434 {
3435 bottom += m_rowHeights[i];
3436 m_rowBottoms[i] = bottom;
3437 }
3438 CalcDimensions();
3439 }
3440 return TRUE;
3441
3442 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
3443 {
3444 int numRows = msg.GetCommandInt();
3445 for ( i = 0; i < numRows; i++ )
3446 {
3447 m_rowHeights.Add( m_defaultRowHeight );
3448 m_rowBottoms.Add( 0 );
3449 }
3450
3451 int oldNumRows = m_numRows;
3452 m_numRows += numRows;
3453
3454 int bottom = 0;
3455 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
3456
3457 for ( i = oldNumRows; i < m_numRows; i++ )
3458 {
3459 bottom += m_rowHeights[i];
3460 m_rowBottoms[i] = bottom;
3461 }
3462 CalcDimensions();
3463 }
3464 return TRUE;
3465
3466 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
3467 {
3468 size_t pos = msg.GetCommandInt();
3469 int numRows = msg.GetCommandInt2();
3470 for ( i = 0; i < numRows; i++ )
3471 {
3472 m_rowHeights.Remove( pos );
3473 m_rowBottoms.Remove( pos );
3474 }
3475 m_numRows -= numRows;
3476
3477 if ( !m_numRows )
3478 {
3479 m_numCols = 0;
3480 m_colWidths.Clear();
3481 m_colRights.Clear();
3482 m_currentCellCoords = wxGridNoCellCoords;
3483 }
3484 else
3485 {
3486 if ( m_currentCellCoords.GetRow() >= m_numRows )
3487 m_currentCellCoords.Set( 0, 0 );
3488
3489 int h = 0;
3490 for ( i = 0; i < m_numRows; i++ )
3491 {
3492 h += m_rowHeights[i];
3493 m_rowBottoms[i] = h;
3494 }
3495 }
3496
3497 CalcDimensions();
3498 }
3499 return TRUE;
3500
3501 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
3502 {
3503 size_t pos = msg.GetCommandInt();
3504 int numCols = msg.GetCommandInt2();
3505 for ( i = 0; i < numCols; i++ )
3506 {
3507 m_colWidths.Insert( m_defaultColWidth, pos );
3508 m_colRights.Insert( 0, pos );
3509 }
3510 m_numCols += numCols;
3511
3512 int right = 0;
3513 if ( pos > 0 ) right = m_colRights[pos-1];
3514
3515 for ( i = pos; i < m_numCols; i++ )
3516 {
3517 right += m_colWidths[i];
3518 m_colRights[i] = right;
3519 }
3520 CalcDimensions();
3521 }
3522 return TRUE;
3523
3524 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
3525 {
3526 int numCols = msg.GetCommandInt();
3527 for ( i = 0; i < numCols; i++ )
3528 {
3529 m_colWidths.Add( m_defaultColWidth );
3530 m_colRights.Add( 0 );
3531 }
3532
3533 int oldNumCols = m_numCols;
3534 m_numCols += numCols;
3535
3536 int right = 0;
3537 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
3538
3539 for ( i = oldNumCols; i < m_numCols; i++ )
3540 {
3541 right += m_colWidths[i];
3542 m_colRights[i] = right;
3543 }
3544 CalcDimensions();
3545 }
3546 return TRUE;
3547
3548 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
3549 {
3550 size_t pos = msg.GetCommandInt();
3551 int numCols = msg.GetCommandInt2();
3552 for ( i = 0; i < numCols; i++ )
3553 {
3554 m_colWidths.Remove( pos );
3555 m_colRights.Remove( pos );
3556 }
3557 m_numCols -= numCols;
3558
3559 if ( !m_numCols )
3560 {
3561 #if 0 // leave the row alone here so that AppendCols will work subsequently
3562 m_numRows = 0;
3563 m_rowHeights.Clear();
3564 m_rowBottoms.Clear();
3565 #endif
3566 m_currentCellCoords = wxGridNoCellCoords;
3567 }
3568 else
3569 {
3570 if ( m_currentCellCoords.GetCol() >= m_numCols )
3571 m_currentCellCoords.Set( 0, 0 );
3572
3573 int w = 0;
3574 for ( i = 0; i < m_numCols; i++ )
3575 {
3576 w += m_colWidths[i];
3577 m_colRights[i] = w;
3578 }
3579 }
3580 CalcDimensions();
3581 }
3582 return TRUE;
3583 }
3584
3585 return FALSE;
3586 }
3587
3588
3589 void wxGrid::CalcRowLabelsExposed( wxRegion& reg )
3590 {
3591 wxRegionIterator iter( reg );
3592 wxRect r;
3593
3594 m_rowLabelsExposed.Empty();
3595
3596 int top, bottom;
3597 while ( iter )
3598 {
3599 r = iter.GetRect();
3600
3601 // TODO: remove this when we can...
3602 // There is a bug in wxMotif that gives garbage update
3603 // rectangles if you jump-scroll a long way by clicking the
3604 // scrollbar with middle button. This is a work-around
3605 //
3606 #if defined(__WXMOTIF__)
3607 int cw, ch;
3608 m_gridWin->GetClientSize( &cw, &ch );
3609 if ( r.GetTop() > ch ) r.SetTop( 0 );
3610 r.SetBottom( wxMin( r.GetBottom(), ch ) );
3611 #endif
3612
3613 // logical bounds of update region
3614 //
3615 int dummy;
3616 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
3617 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
3618
3619 // find the row labels within these bounds
3620 //
3621 int row;
3622 for ( row = 0; row < m_numRows; row++ )
3623 {
3624 if ( GetRowBottom(row) < top )
3625 continue;
3626
3627 if ( GetRowTop(row) > bottom )
3628 break;
3629
3630 m_rowLabelsExposed.Add( row );
3631 }
3632
3633 iter++ ;
3634 }
3635 }
3636
3637
3638 void wxGrid::CalcColLabelsExposed( wxRegion& reg )
3639 {
3640 wxRegionIterator iter( reg );
3641 wxRect r;
3642
3643 m_colLabelsExposed.Empty();
3644
3645 int left, right;
3646 while ( iter )
3647 {
3648 r = iter.GetRect();
3649
3650 // TODO: remove this when we can...
3651 // There is a bug in wxMotif that gives garbage update
3652 // rectangles if you jump-scroll a long way by clicking the
3653 // scrollbar with middle button. This is a work-around
3654 //
3655 #if defined(__WXMOTIF__)
3656 int cw, ch;
3657 m_gridWin->GetClientSize( &cw, &ch );
3658 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
3659 r.SetRight( wxMin( r.GetRight(), cw ) );
3660 #endif
3661
3662 // logical bounds of update region
3663 //
3664 int dummy;
3665 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
3666 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
3667
3668 // find the cells within these bounds
3669 //
3670 int col;
3671 for ( col = 0; col < m_numCols; col++ )
3672 {
3673 if ( GetColRight(col) < left )
3674 continue;
3675
3676 if ( GetColLeft(col) > right )
3677 break;
3678
3679 m_colLabelsExposed.Add( col );
3680 }
3681
3682 iter++ ;
3683 }
3684 }
3685
3686
3687 void wxGrid::CalcCellsExposed( wxRegion& reg )
3688 {
3689 wxRegionIterator iter( reg );
3690 wxRect r;
3691
3692 m_cellsExposed.Empty();
3693 m_rowsExposed.Empty();
3694 m_colsExposed.Empty();
3695
3696 int left, top, right, bottom;
3697 while ( iter )
3698 {
3699 r = iter.GetRect();
3700
3701 // TODO: remove this when we can...
3702 // There is a bug in wxMotif that gives garbage update
3703 // rectangles if you jump-scroll a long way by clicking the
3704 // scrollbar with middle button. This is a work-around
3705 //
3706 #if defined(__WXMOTIF__)
3707 int cw, ch;
3708 m_gridWin->GetClientSize( &cw, &ch );
3709 if ( r.GetTop() > ch ) r.SetTop( 0 );
3710 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
3711 r.SetRight( wxMin( r.GetRight(), cw ) );
3712 r.SetBottom( wxMin( r.GetBottom(), ch ) );
3713 #endif
3714
3715 // logical bounds of update region
3716 //
3717 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3718 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3719
3720 // find the cells within these bounds
3721 //
3722 int row, col;
3723 for ( row = 0; row < m_numRows; row++ )
3724 {
3725 if ( GetRowBottom(row) <= top )
3726 continue;
3727
3728 if ( GetRowTop(row) > bottom )
3729 break;
3730
3731 m_rowsExposed.Add( row );
3732
3733 for ( col = 0; col < m_numCols; col++ )
3734 {
3735 if ( GetColRight(col) <= left )
3736 continue;
3737
3738 if ( GetColLeft(col) > right )
3739 break;
3740
3741 if ( m_colsExposed.Index( col ) == wxNOT_FOUND )
3742 m_colsExposed.Add( col );
3743 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
3744 }
3745 }
3746
3747 iter++;
3748 }
3749 }
3750
3751
3752 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
3753 {
3754 int x, y, row;
3755 wxPoint pos( event.GetPosition() );
3756 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
3757
3758 if ( event.Dragging() )
3759 {
3760 m_isDragging = TRUE;
3761
3762 if ( event.LeftIsDown() )
3763 {
3764 switch( m_cursorMode )
3765 {
3766 case WXGRID_CURSOR_RESIZE_ROW:
3767 {
3768 int cw, ch, left, dummy;
3769 m_gridWin->GetClientSize( &cw, &ch );
3770 CalcUnscrolledPosition( 0, 0, &left, &dummy );
3771
3772 wxClientDC dc( m_gridWin );
3773 PrepareDC( dc );
3774 y = wxMax( y,
3775 GetRowTop(m_dragRowOrCol) +
3776 GetRowMinimalHeight(m_dragRowOrCol) );
3777 dc.SetLogicalFunction(wxINVERT);
3778 if ( m_dragLastPos >= 0 )
3779 {
3780 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
3781 }
3782 dc.DrawLine( left, y, left+cw, y );
3783 m_dragLastPos = y;
3784 }
3785 break;
3786
3787 case WXGRID_CURSOR_SELECT_ROW:
3788 if ( (row = YToRow( y )) >= 0 &&
3789 !IsInSelection( row, 0 ) )
3790 {
3791 SelectRow( row, TRUE );
3792 }
3793
3794 // default label to suppress warnings about "enumeration value
3795 // 'xxx' not handled in switch
3796 default:
3797 break;
3798 }
3799 }
3800 return;
3801 }
3802
3803 m_isDragging = FALSE;
3804
3805
3806 // ------------ Entering or leaving the window
3807 //
3808 if ( event.Entering() || event.Leaving() )
3809 {
3810 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
3811 }
3812
3813
3814 // ------------ Left button pressed
3815 //
3816 else if ( event.LeftDown() )
3817 {
3818 // don't send a label click event for a hit on the
3819 // edge of the row label - this is probably the user
3820 // wanting to resize the row
3821 //
3822 if ( YToEdgeOfRow(y) < 0 )
3823 {
3824 row = YToRow(y);
3825 if ( row >= 0 &&
3826 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
3827 {
3828 SelectRow( row, event.ShiftDown() );
3829 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
3830 }
3831 }
3832 else
3833 {
3834 // starting to drag-resize a row
3835 //
3836 if ( CanDragRowSize() )
3837 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
3838 }
3839 }
3840
3841
3842 // ------------ Left double click
3843 //
3844 else if (event.LeftDClick() )
3845 {
3846 if ( YToEdgeOfRow(y) < 0 )
3847 {
3848 row = YToRow(y);
3849 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
3850 }
3851 }
3852
3853
3854 // ------------ Left button released
3855 //
3856 else if ( event.LeftUp() )
3857 {
3858 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
3859 {
3860 DoEndDragResizeRow();
3861
3862 // Note: we are ending the event *after* doing
3863 // default processing in this case
3864 //
3865 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
3866 }
3867
3868 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
3869 m_dragLastPos = -1;
3870 }
3871
3872
3873 // ------------ Right button down
3874 //
3875 else if ( event.RightDown() )
3876 {
3877 row = YToRow(y);
3878 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
3879 {
3880 // no default action at the moment
3881 }
3882 }
3883
3884
3885 // ------------ Right double click
3886 //
3887 else if ( event.RightDClick() )
3888 {
3889 row = YToRow(y);
3890 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
3891 {
3892 // no default action at the moment
3893 }
3894 }
3895
3896
3897 // ------------ No buttons down and mouse moving
3898 //
3899 else if ( event.Moving() )
3900 {
3901 m_dragRowOrCol = YToEdgeOfRow( y );
3902 if ( m_dragRowOrCol >= 0 )
3903 {
3904 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
3905 {
3906 // don't capture the mouse yet
3907 if ( CanDragRowSize() )
3908 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
3909 }
3910 }
3911 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
3912 {
3913 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
3914 }
3915 }
3916 }
3917
3918
3919 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
3920 {
3921 int x, y, col;
3922 wxPoint pos( event.GetPosition() );
3923 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
3924
3925 if ( event.Dragging() )
3926 {
3927 m_isDragging = TRUE;
3928
3929 if ( event.LeftIsDown() )
3930 {
3931 switch( m_cursorMode )
3932 {
3933 case WXGRID_CURSOR_RESIZE_COL:
3934 {
3935 int cw, ch, dummy, top;
3936 m_gridWin->GetClientSize( &cw, &ch );
3937 CalcUnscrolledPosition( 0, 0, &dummy, &top );
3938
3939 wxClientDC dc( m_gridWin );
3940 PrepareDC( dc );
3941
3942 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
3943 GetColMinimalWidth(m_dragRowOrCol));
3944 dc.SetLogicalFunction(wxINVERT);
3945 if ( m_dragLastPos >= 0 )
3946 {
3947 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
3948 }
3949 dc.DrawLine( x, top, x, top+ch );
3950 m_dragLastPos = x;
3951 }
3952 break;
3953
3954 case WXGRID_CURSOR_SELECT_COL:
3955 if ( (col = XToCol( x )) >= 0 &&
3956 !IsInSelection( 0, col ) )
3957 {
3958 SelectCol( col, TRUE );
3959 }
3960
3961 // default label to suppress warnings about "enumeration value
3962 // 'xxx' not handled in switch
3963 default:
3964 break;
3965 }
3966 }
3967 return;
3968 }
3969
3970 m_isDragging = FALSE;
3971
3972
3973 // ------------ Entering or leaving the window
3974 //
3975 if ( event.Entering() || event.Leaving() )
3976 {
3977 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
3978 }
3979
3980
3981 // ------------ Left button pressed
3982 //
3983 else if ( event.LeftDown() )
3984 {
3985 // don't send a label click event for a hit on the
3986 // edge of the col label - this is probably the user
3987 // wanting to resize the col
3988 //
3989 if ( XToEdgeOfCol(x) < 0 )
3990 {
3991 col = XToCol(x);
3992 if ( col >= 0 &&
3993 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
3994 {
3995 SelectCol( col, event.ShiftDown() );
3996 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
3997 }
3998 }
3999 else
4000 {
4001 // starting to drag-resize a col
4002 //
4003 if ( CanDragColSize() )
4004 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
4005 }
4006 }
4007
4008
4009 // ------------ Left double click
4010 //
4011 if ( event.LeftDClick() )
4012 {
4013 if ( XToEdgeOfCol(x) < 0 )
4014 {
4015 col = XToCol(x);
4016 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
4017 }
4018 }
4019
4020
4021 // ------------ Left button released
4022 //
4023 else if ( event.LeftUp() )
4024 {
4025 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4026 {
4027 DoEndDragResizeCol();
4028
4029 // Note: we are ending the event *after* doing
4030 // default processing in this case
4031 //
4032 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
4033 }
4034
4035 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
4036 m_dragLastPos = -1;
4037 }
4038
4039
4040 // ------------ Right button down
4041 //
4042 else if ( event.RightDown() )
4043 {
4044 col = XToCol(x);
4045 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
4046 {
4047 // no default action at the moment
4048 }
4049 }
4050
4051
4052 // ------------ Right double click
4053 //
4054 else if ( event.RightDClick() )
4055 {
4056 col = XToCol(x);
4057 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
4058 {
4059 // no default action at the moment
4060 }
4061 }
4062
4063
4064 // ------------ No buttons down and mouse moving
4065 //
4066 else if ( event.Moving() )
4067 {
4068 m_dragRowOrCol = XToEdgeOfCol( x );
4069 if ( m_dragRowOrCol >= 0 )
4070 {
4071 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4072 {
4073 // don't capture the cursor yet
4074 if ( CanDragColSize() )
4075 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
4076 }
4077 }
4078 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
4079 {
4080 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
4081 }
4082 }
4083 }
4084
4085
4086 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
4087 {
4088 if ( event.LeftDown() )
4089 {
4090 // indicate corner label by having both row and
4091 // col args == -1
4092 //
4093 if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
4094 {
4095 SelectAll();
4096 }
4097 }
4098
4099 else if ( event.LeftDClick() )
4100 {
4101 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
4102 }
4103
4104 else if ( event.RightDown() )
4105 {
4106 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
4107 {
4108 // no default action at the moment
4109 }
4110 }
4111
4112 else if ( event.RightDClick() )
4113 {
4114 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
4115 {
4116 // no default action at the moment
4117 }
4118 }
4119 }
4120
4121 void wxGrid::ChangeCursorMode(CursorMode mode,
4122 wxWindow *win,
4123 bool captureMouse)
4124 {
4125 #ifdef __WXDEBUG__
4126 static const wxChar *cursorModes[] =
4127 {
4128 _T("SELECT_CELL"),
4129 _T("RESIZE_ROW"),
4130 _T("RESIZE_COL"),
4131 _T("SELECT_ROW"),
4132 _T("SELECT_COL")
4133 };
4134
4135 wxLogTrace(_T("grid"),
4136 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
4137 win == m_colLabelWin ? _T("colLabelWin")
4138 : win ? _T("rowLabelWin")
4139 : _T("gridWin"),
4140 cursorModes[m_cursorMode], cursorModes[mode]);
4141 #endif // __WXDEBUG__
4142
4143 if ( mode == m_cursorMode )
4144 return;
4145
4146 if ( !win )
4147 {
4148 // by default use the grid itself
4149 win = m_gridWin;
4150 }
4151
4152 if ( m_winCapture )
4153 {
4154 m_winCapture->ReleaseMouse();
4155 m_winCapture = (wxWindow *)NULL;
4156 }
4157
4158 m_cursorMode = mode;
4159
4160 switch ( m_cursorMode )
4161 {
4162 case WXGRID_CURSOR_RESIZE_ROW:
4163 win->SetCursor( m_rowResizeCursor );
4164 break;
4165
4166 case WXGRID_CURSOR_RESIZE_COL:
4167 win->SetCursor( m_colResizeCursor );
4168 break;
4169
4170 default:
4171 win->SetCursor( *wxSTANDARD_CURSOR );
4172 }
4173
4174 // we need to capture mouse when resizing
4175 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
4176 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
4177
4178 if ( captureMouse && resize )
4179 {
4180 win->CaptureMouse();
4181 m_winCapture = win;
4182 }
4183 }
4184
4185 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
4186 {
4187 int x, y;
4188 wxPoint pos( event.GetPosition() );
4189 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
4190
4191 wxGridCellCoords coords;
4192 XYToCell( x, y, coords );
4193
4194 if ( event.Dragging() )
4195 {
4196 //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
4197
4198 // Don't start doing anything until the mouse has been drug at
4199 // least 3 pixels in any direction...
4200 if (! m_isDragging)
4201 {
4202 if (m_startDragPos == wxDefaultPosition)
4203 {
4204 m_startDragPos = pos;
4205 return;
4206 }
4207 if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
4208 return;
4209 }
4210
4211 m_isDragging = TRUE;
4212 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4213 {
4214 // Hide the edit control, so it
4215 // won't interfer with drag-shrinking.
4216 if ( IsCellEditControlEnabled() )
4217 {
4218 HideCellEditControl();
4219 SaveEditControlValue();
4220 }
4221
4222 // Have we captured the mouse yet?
4223 if (! m_winCapture)
4224 {
4225 m_winCapture = m_gridWin;
4226 m_winCapture->CaptureMouse();
4227 }
4228
4229 if ( coords != wxGridNoCellCoords )
4230 {
4231 if ( !IsSelection() )
4232 {
4233 SelectBlock( coords, coords );
4234 }
4235 else
4236 {
4237 SelectBlock( m_currentCellCoords, coords );
4238 }
4239
4240 if (! IsVisible(coords))
4241 {
4242 MakeCellVisible(coords);
4243 // TODO: need to introduce a delay or something here. The
4244 // scrolling is way to fast, at least on MSW.
4245 }
4246 }
4247 }
4248 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4249 {
4250 int cw, ch, left, dummy;
4251 m_gridWin->GetClientSize( &cw, &ch );
4252 CalcUnscrolledPosition( 0, 0, &left, &dummy );
4253
4254 wxClientDC dc( m_gridWin );
4255 PrepareDC( dc );
4256 y = wxMax( y, GetRowTop(m_dragRowOrCol) +
4257 GetRowMinimalHeight(m_dragRowOrCol) );
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 // init both of them to avoid compiler warnings, even if weo nly need one
7261 int row = -1,
7262 col = -1;
7263 if ( column )
7264 col = colOrRow;
7265 else
7266 row = colOrRow;
7267
7268 wxCoord extent, extentMax = 0;
7269 int max = column ? m_numRows : m_numCols;
7270 for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
7271 {
7272 if ( column )
7273 row = rowOrCol;
7274 else
7275 col = rowOrCol;
7276
7277 wxGridCellAttr* attr = GetCellAttr(row, col);
7278 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
7279 if ( renderer )
7280 {
7281 wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
7282 extent = column ? size.x : size.y;
7283 if ( extent > extentMax )
7284 {
7285 extentMax = extent;
7286 }
7287
7288 renderer->DecRef();
7289 }
7290
7291 attr->DecRef();
7292 }
7293
7294 // now also compare with the column label extent
7295 wxCoord w, h;
7296 dc.SetFont( GetLabelFont() );
7297
7298 if ( column )
7299 dc.GetTextExtent( GetColLabelValue(col), &w, &h );
7300 else
7301 dc.GetTextExtent( GetRowLabelValue(col), &w, &h );
7302
7303 extent = column ? w : h;
7304 if ( extent > extentMax )
7305 {
7306 extentMax = extent;
7307 }
7308
7309 if ( !extentMax )
7310 {
7311 // empty column - give default extent (notice that if extentMax is less
7312 // than default extent but != 0, it's ok)
7313 extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
7314 }
7315 else
7316 {
7317 if ( column )
7318 {
7319 // leave some space around text
7320 extentMax += 10;
7321 }
7322 }
7323
7324 if ( column )
7325 SetColSize(col, extentMax);
7326 else
7327 SetRowSize(row, extentMax);
7328
7329 if ( setAsMin )
7330 {
7331 if ( column )
7332 SetColMinimalWidth(col, extentMax);
7333 else
7334 SetRowMinimalHeight(row, extentMax);
7335 }
7336 }
7337
7338 int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
7339 {
7340 int width = m_rowLabelWidth;
7341
7342 for ( int col = 0; col < m_numCols; col++ )
7343 {
7344 if ( !calcOnly )
7345 {
7346 AutoSizeColumn(col, setAsMin);
7347 }
7348
7349 width += GetColWidth(col);
7350 }
7351
7352 return width;
7353 }
7354
7355 int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
7356 {
7357 int height = m_colLabelHeight;
7358
7359 for ( int row = 0; row < m_numRows; row++ )
7360 {
7361 if ( !calcOnly )
7362 {
7363 AutoSizeRow(row, setAsMin);
7364 }
7365
7366 height += GetRowHeight(row);
7367 }
7368
7369 return height;
7370 }
7371
7372 void wxGrid::AutoSize()
7373 {
7374 // set the size too
7375 SetSize(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
7376 }
7377
7378 wxSize wxGrid::DoGetBestSize() const
7379 {
7380 // don't set sizes, only calculate them
7381 wxGrid *self = (wxGrid *)this; // const_cast
7382
7383 return wxSize(self->SetOrCalcColumnSizes(TRUE),
7384 self->SetOrCalcRowSizes(TRUE));
7385 }
7386
7387 void wxGrid::Fit()
7388 {
7389 AutoSize();
7390 }
7391
7392 // ----------------------------------------------------------------------------
7393 // cell value accessor functions
7394 // ----------------------------------------------------------------------------
7395
7396 void wxGrid::SetCellValue( int row, int col, const wxString& s )
7397 {
7398 if ( m_table )
7399 {
7400 m_table->SetValue( row, col, s.c_str() );
7401 if ( !GetBatchCount() )
7402 {
7403 wxClientDC dc( m_gridWin );
7404 PrepareDC( dc );
7405 DrawCell( dc, wxGridCellCoords(row, col) );
7406 }
7407
7408 if ( m_currentCellCoords.GetRow() == row &&
7409 m_currentCellCoords.GetCol() == col &&
7410 IsCellEditControlEnabled())
7411 {
7412 HideCellEditControl();
7413 ShowCellEditControl(); // will reread data from table
7414 }
7415 }
7416 }
7417
7418
7419 //
7420 // ------ Block, row and col selection
7421 //
7422
7423 void wxGrid::SelectRow( int row, bool addToSelected )
7424 {
7425 wxRect r;
7426
7427 if ( IsSelection() && addToSelected )
7428 {
7429 wxRect rect[4];
7430 bool need_refresh[4];
7431 need_refresh[0] =
7432 need_refresh[1] =
7433 need_refresh[2] =
7434 need_refresh[3] = FALSE;
7435
7436 int i;
7437
7438 wxCoord oldLeft = m_selectedTopLeft.GetCol();
7439 wxCoord oldTop = m_selectedTopLeft.GetRow();
7440 wxCoord oldRight = m_selectedBottomRight.GetCol();
7441 wxCoord oldBottom = m_selectedBottomRight.GetRow();
7442
7443 if ( oldTop > row )
7444 {
7445 need_refresh[0] = TRUE;
7446 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
7447 wxGridCellCoords ( oldTop - 1,
7448 m_numCols - 1 ) );
7449 m_selectedTopLeft.SetRow( row );
7450 }
7451
7452 if ( oldLeft > 0 )
7453 {
7454 need_refresh[1] = TRUE;
7455 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
7456 wxGridCellCoords ( oldBottom,
7457 oldLeft - 1 ) );
7458
7459 m_selectedTopLeft.SetCol( 0 );
7460 }
7461
7462 if ( oldBottom < row )
7463 {
7464 need_refresh[2] = TRUE;
7465 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
7466 wxGridCellCoords ( row,
7467 m_numCols - 1 ) );
7468 m_selectedBottomRight.SetRow( row );
7469 }
7470
7471 if ( oldRight < m_numCols - 1 )
7472 {
7473 need_refresh[3] = TRUE;
7474 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
7475 oldRight + 1 ),
7476 wxGridCellCoords ( oldBottom,
7477 m_numCols - 1 ) );
7478 m_selectedBottomRight.SetCol( m_numCols - 1 );
7479 }
7480
7481 for (i = 0; i < 4; i++ )
7482 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
7483 m_gridWin->Refresh( FALSE, &(rect[i]) );
7484 }
7485 else
7486 {
7487 r = SelectionToDeviceRect();
7488 ClearSelection();
7489 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
7490
7491 m_selectedTopLeft.Set( row, 0 );
7492 m_selectedBottomRight.Set( row, m_numCols-1 );
7493 r = SelectionToDeviceRect();
7494 m_gridWin->Refresh( FALSE, &r );
7495 }
7496
7497 wxGridRangeSelectEvent gridEvt( GetId(),
7498 wxEVT_GRID_RANGE_SELECT,
7499 this,
7500 m_selectedTopLeft,
7501 m_selectedBottomRight );
7502
7503 GetEventHandler()->ProcessEvent(gridEvt);
7504 }
7505
7506
7507 void wxGrid::SelectCol( int col, bool addToSelected )
7508 {
7509 if ( IsSelection() && addToSelected )
7510 {
7511 wxRect rect[4];
7512 bool need_refresh[4];
7513 need_refresh[0] =
7514 need_refresh[1] =
7515 need_refresh[2] =
7516 need_refresh[3] = FALSE;
7517 int i;
7518
7519 wxCoord oldLeft = m_selectedTopLeft.GetCol();
7520 wxCoord oldTop = m_selectedTopLeft.GetRow();
7521 wxCoord oldRight = m_selectedBottomRight.GetCol();
7522 wxCoord oldBottom = m_selectedBottomRight.GetRow();
7523
7524 if ( oldLeft > col )
7525 {
7526 need_refresh[0] = TRUE;
7527 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
7528 wxGridCellCoords ( m_numRows - 1,
7529 oldLeft - 1 ) );
7530 m_selectedTopLeft.SetCol( col );
7531 }
7532
7533 if ( oldTop > 0 )
7534 {
7535 need_refresh[1] = TRUE;
7536 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
7537 wxGridCellCoords ( oldTop - 1,
7538 oldRight ) );
7539 m_selectedTopLeft.SetRow( 0 );
7540 }
7541
7542 if ( oldRight < col )
7543 {
7544 need_refresh[2] = TRUE;
7545 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
7546 wxGridCellCoords ( m_numRows - 1,
7547 col ) );
7548 m_selectedBottomRight.SetCol( col );
7549 }
7550
7551 if ( oldBottom < m_numRows - 1 )
7552 {
7553 need_refresh[3] = TRUE;
7554 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
7555 oldLeft ),
7556 wxGridCellCoords ( m_numRows - 1,
7557 oldRight ) );
7558 m_selectedBottomRight.SetRow( m_numRows - 1 );
7559 }
7560
7561 for (i = 0; i < 4; i++ )
7562 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
7563 m_gridWin->Refresh( FALSE, &(rect[i]) );
7564 }
7565 else
7566 {
7567 wxRect r;
7568
7569 r = SelectionToDeviceRect();
7570 ClearSelection();
7571 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
7572
7573 m_selectedTopLeft.Set( 0, col );
7574 m_selectedBottomRight.Set( m_numRows-1, col );
7575 r = SelectionToDeviceRect();
7576 m_gridWin->Refresh( FALSE, &r );
7577 }
7578
7579 wxGridRangeSelectEvent gridEvt( GetId(),
7580 wxEVT_GRID_RANGE_SELECT,
7581 this,
7582 m_selectedTopLeft,
7583 m_selectedBottomRight );
7584
7585 GetEventHandler()->ProcessEvent(gridEvt);
7586 }
7587
7588
7589 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
7590 {
7591 int temp;
7592 wxGridCellCoords updateTopLeft, updateBottomRight;
7593
7594 if ( topRow > bottomRow )
7595 {
7596 temp = topRow;
7597 topRow = bottomRow;
7598 bottomRow = temp;
7599 }
7600
7601 if ( leftCol > rightCol )
7602 {
7603 temp = leftCol;
7604 leftCol = rightCol;
7605 rightCol = temp;
7606 }
7607
7608 updateTopLeft = wxGridCellCoords( topRow, leftCol );
7609 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
7610
7611 if ( m_selectedTopLeft != updateTopLeft ||
7612 m_selectedBottomRight != updateBottomRight )
7613 {
7614 // Compute two optimal update rectangles:
7615 // Either one rectangle is a real subset of the
7616 // other, or they are (almost) disjoint!
7617 wxRect rect[4];
7618 bool need_refresh[4];
7619 need_refresh[0] =
7620 need_refresh[1] =
7621 need_refresh[2] =
7622 need_refresh[3] = FALSE;
7623 int i;
7624
7625 // Store intermediate values
7626 wxCoord oldLeft = m_selectedTopLeft.GetCol();
7627 wxCoord oldTop = m_selectedTopLeft.GetRow();
7628 wxCoord oldRight = m_selectedBottomRight.GetCol();
7629 wxCoord oldBottom = m_selectedBottomRight.GetRow();
7630
7631 // Determine the outer/inner coordinates.
7632 if (oldLeft > leftCol)
7633 {
7634 temp = oldLeft;
7635 oldLeft = leftCol;
7636 leftCol = temp;
7637 }
7638 if (oldTop > topRow )
7639 {
7640 temp = oldTop;
7641 oldTop = topRow;
7642 topRow = temp;
7643 }
7644 if (oldRight < rightCol )
7645 {
7646 temp = oldRight;
7647 oldRight = rightCol;
7648 rightCol = temp;
7649 }
7650 if (oldBottom < bottomRow)
7651 {
7652 temp = oldBottom;
7653 oldBottom = bottomRow;
7654 bottomRow = temp;
7655 }
7656
7657 // Now, either the stuff marked old is the outer
7658 // rectangle or we don't have a situation where one
7659 // is contained in the other.
7660
7661 if ( oldLeft < leftCol )
7662 {
7663 need_refresh[0] = TRUE;
7664 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
7665 oldLeft ),
7666 wxGridCellCoords ( oldBottom,
7667 leftCol - 1 ) );
7668 }
7669
7670 if ( oldTop < topRow )
7671 {
7672 need_refresh[1] = TRUE;
7673 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
7674 leftCol ),
7675 wxGridCellCoords ( topRow - 1,
7676 rightCol ) );
7677 }
7678
7679 if ( oldRight > rightCol )
7680 {
7681 need_refresh[2] = TRUE;
7682 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
7683 rightCol + 1 ),
7684 wxGridCellCoords ( oldBottom,
7685 oldRight ) );
7686 }
7687
7688 if ( oldBottom > bottomRow )
7689 {
7690 need_refresh[3] = TRUE;
7691 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
7692 leftCol ),
7693 wxGridCellCoords ( oldBottom,
7694 rightCol ) );
7695 }
7696
7697
7698 // Change Selection
7699 m_selectedTopLeft = updateTopLeft;
7700 m_selectedBottomRight = updateBottomRight;
7701
7702 // various Refresh() calls
7703 for (i = 0; i < 4; i++ )
7704 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
7705 m_gridWin->Refresh( FALSE, &(rect[i]) );
7706 }
7707
7708 // only generate an event if the block is not being selected by
7709 // dragging the mouse (in which case the event will be generated in
7710 // the mouse event handler)
7711 if ( !m_isDragging )
7712 {
7713 wxGridRangeSelectEvent gridEvt( GetId(),
7714 wxEVT_GRID_RANGE_SELECT,
7715 this,
7716 m_selectedTopLeft,
7717 m_selectedBottomRight );
7718
7719 GetEventHandler()->ProcessEvent(gridEvt);
7720 }
7721 }
7722
7723 void wxGrid::SelectAll()
7724 {
7725 m_selectedTopLeft.Set( 0, 0 );
7726 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
7727
7728 m_gridWin->Refresh();
7729 }
7730
7731
7732 void wxGrid::ClearSelection()
7733 {
7734 m_selectedTopLeft = wxGridNoCellCoords;
7735 m_selectedBottomRight = wxGridNoCellCoords;
7736 }
7737
7738
7739 // This function returns the rectangle that encloses the given block
7740 // in device coords clipped to the client size of the grid window.
7741 //
7742 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
7743 const wxGridCellCoords &bottomRight )
7744 {
7745 wxRect rect( wxGridNoCellRect );
7746 wxRect cellRect;
7747
7748 cellRect = CellToRect( topLeft );
7749 if ( cellRect != wxGridNoCellRect )
7750 {
7751 rect = cellRect;
7752 }
7753 else
7754 {
7755 rect = wxRect( 0, 0, 0, 0 );
7756 }
7757
7758 cellRect = CellToRect( bottomRight );
7759 if ( cellRect != wxGridNoCellRect )
7760 {
7761 rect += cellRect;
7762 }
7763 else
7764 {
7765 return wxGridNoCellRect;
7766 }
7767
7768 // convert to scrolled coords
7769 //
7770 int left, top, right, bottom;
7771 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
7772 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
7773
7774 int cw, ch;
7775 m_gridWin->GetClientSize( &cw, &ch );
7776
7777 rect.SetLeft( wxMax(0, left) );
7778 rect.SetTop( wxMax(0, top) );
7779 rect.SetRight( wxMin(cw, right) );
7780 rect.SetBottom( wxMin(ch, bottom) );
7781
7782 return rect;
7783 }
7784
7785
7786
7787 //
7788 // ------ Grid event classes
7789 //
7790
7791 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
7792
7793 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
7794 int row, int col, int x, int y,
7795 bool control, bool shift, bool alt, bool meta )
7796 : wxNotifyEvent( type, id )
7797 {
7798 m_row = row;
7799 m_col = col;
7800 m_x = x;
7801 m_y = y;
7802 m_control = control;
7803 m_shift = shift;
7804 m_alt = alt;
7805 m_meta = meta;
7806
7807 SetEventObject(obj);
7808 }
7809
7810
7811 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
7812
7813 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
7814 int rowOrCol, int x, int y,
7815 bool control, bool shift, bool alt, bool meta )
7816 : wxNotifyEvent( type, id )
7817 {
7818 m_rowOrCol = rowOrCol;
7819 m_x = x;
7820 m_y = y;
7821 m_control = control;
7822 m_shift = shift;
7823 m_alt = alt;
7824 m_meta = meta;
7825
7826 SetEventObject(obj);
7827 }
7828
7829
7830 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
7831
7832 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
7833 const wxGridCellCoords& topLeft,
7834 const wxGridCellCoords& bottomRight,
7835 bool control, bool shift, bool alt, bool meta )
7836 : wxNotifyEvent( type, id )
7837 {
7838 m_topLeft = topLeft;
7839 m_bottomRight = bottomRight;
7840 m_control = control;
7841 m_shift = shift;
7842 m_alt = alt;
7843 m_meta = meta;
7844
7845 SetEventObject(obj);
7846 }
7847
7848
7849 #endif // ifndef wxUSE_NEW_GRID
7850