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