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