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