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