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