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