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