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