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