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