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