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