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