wxGridCellEditor plugged in and operational for strings.
[wxWidgets.git] / src / generic / grid.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 // Name: 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 precompilation, 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 #endif
43
44 // this include needs to be outside precomp for BCC
45 #include "wx/textfile.h"
46
47 #include "wx/grid.h"
48
49
50 // ----------------------------------------------------------------------------
51 // array classes
52 // ----------------------------------------------------------------------------
53
54 WX_DEFINE_ARRAY(wxGridCellAttr *, wxArrayAttrs);
55
56 struct wxGridCellWithAttr
57 {
58 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
59 : coords(row, col), attr(attr_)
60 {
61 }
62
63 ~wxGridCellWithAttr()
64 {
65 attr->DecRef();
66 }
67
68 wxGridCellCoords coords;
69 wxGridCellAttr *attr;
70 };
71
72 WX_DECLARE_OBJARRAY(wxGridCellWithAttr, wxGridCellWithAttrArray);
73
74 #include "wx/arrimpl.cpp"
75
76 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
77 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
78
79 // ----------------------------------------------------------------------------
80 // private classes
81 // ----------------------------------------------------------------------------
82
83 class WXDLLEXPORT wxGridRowLabelWindow : public wxWindow
84 {
85 public:
86 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
87 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
88 const wxPoint &pos, const wxSize &size );
89
90 private:
91 wxGrid *m_owner;
92
93 void OnPaint( wxPaintEvent& event );
94 void OnMouseEvent( wxMouseEvent& event );
95 void OnKeyDown( wxKeyEvent& event );
96
97 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
98 DECLARE_EVENT_TABLE()
99 };
100
101
102 class WXDLLEXPORT wxGridColLabelWindow : public wxWindow
103 {
104 public:
105 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
106 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
107 const wxPoint &pos, const wxSize &size );
108
109 private:
110 wxGrid *m_owner;
111
112 void OnPaint( wxPaintEvent &event );
113 void OnMouseEvent( wxMouseEvent& event );
114 void OnKeyDown( wxKeyEvent& event );
115
116 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
117 DECLARE_EVENT_TABLE()
118 };
119
120
121 class WXDLLEXPORT wxGridCornerLabelWindow : public wxWindow
122 {
123 public:
124 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
125 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
126 const wxPoint &pos, const wxSize &size );
127
128 private:
129 wxGrid *m_owner;
130
131 void OnMouseEvent( wxMouseEvent& event );
132 void OnKeyDown( wxKeyEvent& event );
133 void OnPaint( wxPaintEvent& event );
134
135 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
136 DECLARE_EVENT_TABLE()
137 };
138
139 class WXDLLEXPORT wxGridWindow : public wxPanel
140 {
141 public:
142 wxGridWindow()
143 {
144 m_owner = (wxGrid *)NULL;
145 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
146 m_colLabelWin = (wxGridColLabelWindow *)NULL;
147 }
148
149 wxGridWindow( wxGrid *parent,
150 wxGridRowLabelWindow *rowLblWin,
151 wxGridColLabelWindow *colLblWin,
152 wxWindowID id, const wxPoint &pos, const wxSize &size );
153 ~wxGridWindow();
154
155 void ScrollWindow( int dx, int dy, const wxRect *rect );
156
157 private:
158 wxGrid *m_owner;
159 wxGridRowLabelWindow *m_rowLabelWin;
160 wxGridColLabelWindow *m_colLabelWin;
161
162 void OnPaint( wxPaintEvent &event );
163 void OnMouseEvent( wxMouseEvent& event );
164 void OnKeyDown( wxKeyEvent& );
165 void OnEraseBackground( wxEraseEvent& );
166
167
168 DECLARE_DYNAMIC_CLASS(wxGridWindow)
169 DECLARE_EVENT_TABLE()
170 };
171
172
173
174 class wxGridCellEditorEvtHandler : public wxEvtHandler
175 {
176 public:
177 wxGridCellEditorEvtHandler()
178 : m_grid(0), m_editor(0)
179 { }
180 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
181 : m_grid(grid), m_editor(editor)
182 { }
183
184 void OnKeyDown(wxKeyEvent& event);
185
186 private:
187 wxGrid* m_grid;
188 wxGridCellEditor* m_editor;
189 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
190 DECLARE_EVENT_TABLE()
191 };
192
193
194 IMPLEMENT_DYNAMIC_CLASS( wxGridCellEditorEvtHandler, wxEvtHandler )
195 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
196 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
197 END_EVENT_TABLE()
198
199
200
201 // ----------------------------------------------------------------------------
202 // the internal data representation used by wxGridCellAttrProvider
203 // ----------------------------------------------------------------------------
204
205 // this class stores attributes set for cells
206 class WXDLLEXPORT wxGridCellAttrData
207 {
208 public:
209 void SetAttr(wxGridCellAttr *attr, int row, int col);
210 wxGridCellAttr *GetAttr(int row, int col) const;
211
212 private:
213 // searches for the attr for given cell, returns wxNOT_FOUND if not found
214 int FindIndex(int row, int col) const;
215
216 wxGridCellWithAttrArray m_attrs;
217 };
218
219 // this class stores attributes set for rows or columns
220 class WXDLLEXPORT wxGridRowOrColAttrData
221 {
222 public:
223 ~wxGridRowOrColAttrData();
224
225 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
226 wxGridCellAttr *GetAttr(int rowOrCol) const;
227
228 private:
229 wxArrayInt m_rowsOrCols;
230 wxArrayAttrs m_attrs;
231 };
232
233 // NB: this is just a wrapper around 3 objects: one which stores cell
234 // attributes, and 2 others for row/col ones
235 class WXDLLEXPORT wxGridCellAttrProviderData
236 {
237 public:
238 wxGridCellAttrData m_cellAttrs;
239 wxGridRowOrColAttrData m_rowAttrs,
240 m_colAttrs;
241 };
242
243 // ----------------------------------------------------------------------------
244 // conditional compilation
245 // ----------------------------------------------------------------------------
246
247 #ifndef WXGRID_DRAW_LINES
248 #define WXGRID_DRAW_LINES 1
249 #endif
250
251 // ----------------------------------------------------------------------------
252 // globals
253 // ----------------------------------------------------------------------------
254
255 //#define DEBUG_ATTR_CACHE
256 #ifdef DEBUG_ATTR_CACHE
257 static size_t gs_nAttrCacheHits = 0;
258 static size_t gs_nAttrCacheMisses = 0;
259 #endif // DEBUG_ATTR_CACHE
260
261 wxGridCellCoords wxGridNoCellCoords( -1, -1 );
262 wxRect wxGridNoCellRect( -1, -1, -1, -1 );
263
264 // scroll line size
265 // TODO: fixed so far - make configurable later (and also different for x/y)
266 static const size_t GRID_SCROLL_LINE = 10;
267
268 // ============================================================================
269 // implementation
270 // ============================================================================
271
272
273 // ----------------------------------------------------------------------------
274 // wxGridCellEditor
275 // ----------------------------------------------------------------------------
276
277 wxGridCellEditor::wxGridCellEditor()
278 {
279 m_control = NULL;
280 }
281
282
283 wxGridCellEditor::~wxGridCellEditor()
284 {
285 Destroy();
286 }
287
288
289 void wxGridCellEditor::Destroy()
290 {
291 if (m_control) {
292 m_control->Destroy();
293 m_control = NULL;
294 }
295 }
296
297 void wxGridCellEditor::Show(bool show)
298 {
299 wxASSERT_MSG(m_control,
300 wxT("The wxGridCellEditor must be Created first!"));
301 m_control->Show(show);
302 }
303
304 void wxGridCellEditor::SetSize(const wxRect& rect)
305 {
306 wxASSERT_MSG(m_control,
307 wxT("The wxGridCellEditor must be Created first!"));
308 m_control->SetSize(rect);
309 }
310
311 void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
312 {
313 event.Skip();
314 }
315
316
317 void wxGridCellEditor::StartingKey(wxKeyEvent& event)
318 {
319 }
320
321
322
323 wxGridCellTextEditor::wxGridCellTextEditor()
324 {
325 }
326
327 void wxGridCellTextEditor::Create(wxWindow* parent,
328 wxWindowID id,
329 wxEvtHandler* evtHandler)
330 {
331 m_control = new wxTextCtrl(parent, -1, "",
332 wxDefaultPosition, wxDefaultSize
333 #if defined(__WXMSW__)
334 , wxTE_MULTILINE | wxTE_NO_VSCROLL // necessary ???
335 #endif
336 );
337
338 if (evtHandler)
339 m_control->PushEventHandler(evtHandler);
340 }
341
342
343 void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid,
344 wxGridCellAttr* attr)
345 {
346 wxASSERT_MSG(m_control,
347 wxT("The wxGridCellEditor must be Created first!"));
348
349 m_startValue = grid->GetTable()->GetValue(row, col);
350 ((wxTextCtrl*)m_control)->SetValue(m_startValue);
351 ((wxTextCtrl*)m_control)->SetInsertionPointEnd();
352 ((wxTextCtrl*)m_control)->SetFocus();
353
354 // ??? Should we use attr and try to set colours and font?
355 }
356
357
358
359 bool wxGridCellTextEditor::EndEdit(int row, int col, bool saveValue,
360 wxGrid* grid, wxGridCellAttr* attr)
361 {
362 wxASSERT_MSG(m_control,
363 wxT("The wxGridCellEditor must be Created first!"));
364
365 bool changed = FALSE;
366 wxString value = ((wxTextCtrl*)m_control)->GetValue();
367 if (value != m_startValue)
368 changed = TRUE;
369
370 if (changed)
371 grid->GetTable()->SetValue(row, col, value);
372
373 m_startValue = "";
374 ((wxTextCtrl*)m_control)->SetValue(m_startValue);
375
376 return changed;
377 }
378
379
380 void wxGridCellTextEditor::Reset()
381 {
382 wxASSERT_MSG(m_control,
383 wxT("The wxGridCellEditor must be Created first!"));
384
385 ((wxTextCtrl*)m_control)->SetValue(m_startValue);
386 ((wxTextCtrl*)m_control)->SetInsertionPointEnd();
387 }
388
389
390 void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
391 {
392 wxASSERT_MSG(m_control,
393 wxT("The wxGridCellEditor must be Created first!"));
394
395 int code = event.KeyCode();
396 if (code >= 32 && code < 255) {
397 wxString st((char)code);
398 if (! event.ShiftDown())
399 st.LowerCase();
400 ((wxTextCtrl*)m_control)->AppendText(st);
401 }
402 }
403
404
405 void wxGridCellTextEditor::HandleReturn(wxKeyEvent& event)
406 {
407 #if defined(__WXMOTIF__) || defined(__WXGTK__)
408 // wxMotif needs a little extra help...
409 int pos = ((wxTextCtrl*)m_control)->GetInsertionPoint();
410 wxString s( ((wxTextCtrl*)m_control)->GetValue() );
411 s = s.Left(pos) + "\n" + s.Mid(pos);
412 ((wxTextCtrl*)m_control)->SetValue(s);
413 ((wxTextCtrl*)m_control)->SetInsertionPoint( pos );
414 #else
415 // the other ports can handle a Return key press
416 //
417 event.Skip();
418 #endif
419 }
420
421
422 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
423 {
424 switch ( event.KeyCode() )
425 {
426 case WXK_ESCAPE:
427 m_editor->Reset();
428 m_grid->EnableCellEditControl(FALSE);
429 break;
430
431 // case WXK_UP:
432 // case WXK_DOWN:
433 // case WXK_LEFT:
434 // case WXK_RIGHT:
435 // case WXK_PRIOR:
436 // case WXK_NEXT:
437 // case WXK_SPACE:
438 // case WXK_HOME:
439 // case WXK_END:
440 // // send the event to the parent grid, skipping the
441 // // event if nothing happens
442 // //
443 // event.Skip( m_grid->ProcessEvent( event ) );
444 // break;
445
446 case WXK_TAB:
447 case WXK_RETURN:
448 if (!m_grid->ProcessEvent(event))
449 m_editor->HandleReturn(event);
450 break;
451
452
453 default:
454 event.Skip();
455 }
456 }
457
458 // ----------------------------------------------------------------------------
459 // wxGridCellRenderer
460 // ----------------------------------------------------------------------------
461
462 void wxGridCellRenderer::Draw(wxGrid& grid,
463 wxGridCellAttr& attr,
464 wxDC& dc,
465 const wxRect& rect,
466 int row, int col,
467 bool isSelected)
468 {
469 dc.SetBackgroundMode( wxSOLID );
470
471 if ( isSelected )
472 {
473 dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
474 }
475 else
476 {
477 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
478 }
479
480 dc.SetPen( *wxTRANSPARENT_PEN );
481 dc.DrawRectangle(rect);
482 }
483
484 void wxGridCellStringRenderer::Draw(wxGrid& grid,
485 wxGridCellAttr& attr,
486 wxDC& dc,
487 const wxRect& rectCell,
488 int row, int col,
489 bool isSelected)
490 {
491 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
492
493 // now we only have to draw the text
494 dc.SetBackgroundMode( wxTRANSPARENT );
495
496 if ( isSelected )
497 {
498 dc.SetTextBackground( grid.GetSelectionBackground() );
499 dc.SetTextForeground( grid.GetSelectionForeground() );
500 }
501 else
502 {
503 dc.SetTextBackground( attr.GetBackgroundColour() );
504 dc.SetTextForeground( attr.GetTextColour() );
505 }
506 dc.SetFont( attr.GetFont() );
507
508 int hAlign, vAlign;
509 attr.GetAlignment(&hAlign, &vAlign);
510
511 wxRect rect = rectCell;
512 rect.x++;
513 rect.y++;
514 rect.width -= 2;
515 rect.height -= 2;
516
517 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
518 rect, hAlign, vAlign);
519 }
520
521 // ----------------------------------------------------------------------------
522 // wxGridCellAttr
523 // ----------------------------------------------------------------------------
524
525 const wxColour& wxGridCellAttr::GetTextColour() const
526 {
527 if (HasTextColour())
528 return m_colText;
529 else if (m_defGridAttr != this)
530 return m_defGridAttr->GetTextColour();
531 else {
532 wxFAIL_MSG(wxT("Missing default cell attribute"));
533 return wxNullColour;
534 }
535 }
536
537
538 const wxColour& wxGridCellAttr::GetBackgroundColour() const
539 {
540 if (HasBackgroundColour())
541 return m_colBack;
542 else if (m_defGridAttr != this)
543 return m_defGridAttr->GetBackgroundColour();
544 else {
545 wxFAIL_MSG(wxT("Missing default cell attribute"));
546 return wxNullColour;
547 }
548 }
549
550
551 const wxFont& wxGridCellAttr::GetFont() const
552 {
553 if (HasFont())
554 return m_font;
555 else if (m_defGridAttr != this)
556 return m_defGridAttr->GetFont();
557 else {
558 wxFAIL_MSG(wxT("Missing default cell attribute"));
559 return wxNullFont;
560 }
561 }
562
563
564 void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
565 {
566 if (HasAlignment()) {
567 if ( hAlign ) *hAlign = m_hAlign;
568 if ( vAlign ) *vAlign = m_vAlign;
569 }
570 else if (m_defGridAttr != this)
571 m_defGridAttr->GetAlignment(hAlign, vAlign);
572 else {
573 wxFAIL_MSG(wxT("Missing default cell attribute"));
574 }
575 }
576
577
578 wxGridCellRenderer* wxGridCellAttr::GetRenderer() const
579 {
580 if (HasRenderer())
581 return m_renderer;
582 else if (m_defGridAttr != this)
583 return m_defGridAttr->GetRenderer();
584 else {
585 wxFAIL_MSG(wxT("Missing default cell attribute"));
586 return NULL;
587 }
588 }
589
590 wxGridCellEditor* wxGridCellAttr::GetEditor() const
591 {
592 if (HasEditor())
593 return m_editor;
594 else if (m_defGridAttr != this)
595 return m_defGridAttr->GetEditor();
596 else {
597 wxFAIL_MSG(wxT("Missing default cell attribute"));
598 return NULL;
599 }
600 }
601
602 // ----------------------------------------------------------------------------
603 // wxGridCellAttrData
604 // ----------------------------------------------------------------------------
605
606 void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
607 {
608 int n = FindIndex(row, col);
609 if ( n == wxNOT_FOUND )
610 {
611 // add the attribute
612 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
613 }
614 else
615 {
616 if ( attr )
617 {
618 // change the attribute
619 m_attrs[(size_t)n].attr = attr;
620 }
621 else
622 {
623 // remove this attribute
624 m_attrs.RemoveAt((size_t)n);
625 }
626 }
627 }
628
629 wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
630 {
631 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
632
633 int n = FindIndex(row, col);
634 if ( n != wxNOT_FOUND )
635 {
636 attr = m_attrs[(size_t)n].attr;
637 attr->IncRef();
638 }
639
640 return attr;
641 }
642
643 int wxGridCellAttrData::FindIndex(int row, int col) const
644 {
645 size_t count = m_attrs.GetCount();
646 for ( size_t n = 0; n < count; n++ )
647 {
648 const wxGridCellCoords& coords = m_attrs[n].coords;
649 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
650 {
651 return n;
652 }
653 }
654
655 return wxNOT_FOUND;
656 }
657
658 // ----------------------------------------------------------------------------
659 // wxGridRowOrColAttrData
660 // ----------------------------------------------------------------------------
661
662 wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
663 {
664 size_t count = m_attrs.Count();
665 for ( size_t n = 0; n < count; n++ )
666 {
667 m_attrs[n]->DecRef();
668 }
669 }
670
671 wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
672 {
673 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
674
675 int n = m_rowsOrCols.Index(rowOrCol);
676 if ( n != wxNOT_FOUND )
677 {
678 attr = m_attrs[(size_t)n];
679 attr->IncRef();
680 }
681
682 return attr;
683 }
684
685 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
686 {
687 int n = m_rowsOrCols.Index(rowOrCol);
688 if ( n == wxNOT_FOUND )
689 {
690 // add the attribute
691 m_rowsOrCols.Add(rowOrCol);
692 m_attrs.Add(attr);
693 }
694 else
695 {
696 if ( attr )
697 {
698 // change the attribute
699 m_attrs[(size_t)n] = attr;
700 }
701 else
702 {
703 // remove this attribute
704 m_attrs[(size_t)n]->DecRef();
705 m_rowsOrCols.RemoveAt((size_t)n);
706 m_attrs.RemoveAt((size_t)n);
707 }
708 }
709 }
710
711 // ----------------------------------------------------------------------------
712 // wxGridCellAttrProvider
713 // ----------------------------------------------------------------------------
714
715 wxGridCellAttrProvider::wxGridCellAttrProvider()
716 {
717 m_data = (wxGridCellAttrProviderData *)NULL;
718 }
719
720 wxGridCellAttrProvider::~wxGridCellAttrProvider()
721 {
722 delete m_data;
723 }
724
725 void wxGridCellAttrProvider::InitData()
726 {
727 m_data = new wxGridCellAttrProviderData;
728 }
729
730 wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col) const
731 {
732 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
733 if ( m_data )
734 {
735 // first look for the attribute of this specific cell
736 attr = m_data->m_cellAttrs.GetAttr(row, col);
737
738 if ( !attr )
739 {
740 // then look for the col attr (col attributes are more common than
741 // the row ones, hence they have priority)
742 attr = m_data->m_colAttrs.GetAttr(col);
743 }
744
745 if ( !attr )
746 {
747 // finally try the row attributes
748 attr = m_data->m_rowAttrs.GetAttr(row);
749 }
750 }
751
752 return attr;
753 }
754
755 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
756 int row, int col)
757 {
758 if ( !m_data )
759 InitData();
760
761 m_data->m_cellAttrs.SetAttr(attr, row, col);
762 }
763
764 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
765 {
766 if ( !m_data )
767 InitData();
768
769 m_data->m_rowAttrs.SetAttr(attr, row);
770 }
771
772 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
773 {
774 if ( !m_data )
775 InitData();
776
777 m_data->m_colAttrs.SetAttr(attr, col);
778 }
779
780 // ----------------------------------------------------------------------------
781 // wxGridTableBase
782 // ----------------------------------------------------------------------------
783
784 //////////////////////////////////////////////////////////////////////
785 //
786 // Abstract base class for grid data (the model)
787 //
788 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
789
790
791 wxGridTableBase::wxGridTableBase()
792 {
793 m_view = (wxGrid *) NULL;
794 m_attrProvider = (wxGridCellAttrProvider *) NULL;
795 }
796
797 wxGridTableBase::~wxGridTableBase()
798 {
799 delete m_attrProvider;
800 }
801
802 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
803 {
804 delete m_attrProvider;
805 m_attrProvider = attrProvider;
806 }
807
808 wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col)
809 {
810 if ( m_attrProvider )
811 return m_attrProvider->GetAttr(row, col);
812 else
813 return (wxGridCellAttr *)NULL;
814 }
815
816 void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
817 {
818 if ( m_attrProvider )
819 {
820 m_attrProvider->SetAttr(attr, row, col);
821 }
822 else
823 {
824 // as we take ownership of the pointer and don't store it, we must
825 // free it now
826 attr->SafeDecRef();
827 }
828 }
829
830 void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
831 {
832 if ( m_attrProvider )
833 {
834 m_attrProvider->SetRowAttr(attr, row);
835 }
836 else
837 {
838 // as we take ownership of the pointer and don't store it, we must
839 // free it now
840 attr->SafeDecRef();
841 }
842 }
843
844 void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
845 {
846 if ( m_attrProvider )
847 {
848 m_attrProvider->SetColAttr(attr, col);
849 }
850 else
851 {
852 // as we take ownership of the pointer and don't store it, we must
853 // free it now
854 attr->SafeDecRef();
855 }
856 }
857
858 bool wxGridTableBase::InsertRows( size_t pos, size_t numRows )
859 {
860 wxFAIL_MSG( wxT("Called grid table class function InsertRows\n"
861 "but your derived table class does not override this function") );
862
863 return FALSE;
864 }
865
866 bool wxGridTableBase::AppendRows( size_t numRows )
867 {
868 wxFAIL_MSG( wxT("Called grid table class function AppendRows\n"
869 "but your derived table class does not override this function"));
870
871 return FALSE;
872 }
873
874 bool wxGridTableBase::DeleteRows( size_t pos, size_t numRows )
875 {
876 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\n"
877 "but your derived table class does not override this function"));
878
879 return FALSE;
880 }
881
882 bool wxGridTableBase::InsertCols( size_t pos, size_t numCols )
883 {
884 wxFAIL_MSG( wxT("Called grid table class function InsertCols\n"
885 "but your derived table class does not override this function"));
886
887 return FALSE;
888 }
889
890 bool wxGridTableBase::AppendCols( size_t numCols )
891 {
892 wxFAIL_MSG(wxT("Called grid table class function AppendCols\n"
893 "but your derived table class does not override this function"));
894
895 return FALSE;
896 }
897
898 bool wxGridTableBase::DeleteCols( size_t pos, size_t numCols )
899 {
900 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\n"
901 "but your derived table class does not override this function"));
902
903 return FALSE;
904 }
905
906
907 wxString wxGridTableBase::GetRowLabelValue( int row )
908 {
909 wxString s;
910 s << row;
911 return s;
912 }
913
914 wxString wxGridTableBase::GetColLabelValue( int col )
915 {
916 // default col labels are:
917 // cols 0 to 25 : A-Z
918 // cols 26 to 675 : AA-ZZ
919 // etc.
920
921 wxString s;
922 unsigned int i, n;
923 for ( n = 1; ; n++ )
924 {
925 s += (_T('A') + (wxChar)( col%26 ));
926 col = col/26 - 1;
927 if ( col < 0 ) break;
928 }
929
930 // reverse the string...
931 wxString s2;
932 for ( i = 0; i < n; i++ )
933 {
934 s2 += s[n-i-1];
935 }
936
937 return s2;
938 }
939
940
941
942 //////////////////////////////////////////////////////////////////////
943 //
944 // Message class for the grid table to send requests and notifications
945 // to the grid view
946 //
947
948 wxGridTableMessage::wxGridTableMessage()
949 {
950 m_table = (wxGridTableBase *) NULL;
951 m_id = -1;
952 m_comInt1 = -1;
953 m_comInt2 = -1;
954 }
955
956 wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
957 int commandInt1, int commandInt2 )
958 {
959 m_table = table;
960 m_id = id;
961 m_comInt1 = commandInt1;
962 m_comInt2 = commandInt2;
963 }
964
965
966
967 //////////////////////////////////////////////////////////////////////
968 //
969 // A basic grid table for string data. An object of this class will
970 // created by wxGrid if you don't specify an alternative table class.
971 //
972
973 WX_DEFINE_OBJARRAY(wxGridStringArray)
974
975 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
976
977 wxGridStringTable::wxGridStringTable()
978 : wxGridTableBase()
979 {
980 }
981
982 wxGridStringTable::wxGridStringTable( int numRows, int numCols )
983 : wxGridTableBase()
984 {
985 int row, col;
986
987 m_data.Alloc( numRows );
988
989 wxArrayString sa;
990 sa.Alloc( numCols );
991 for ( col = 0; col < numCols; col++ )
992 {
993 sa.Add( wxEmptyString );
994 }
995
996 for ( row = 0; row < numRows; row++ )
997 {
998 m_data.Add( sa );
999 }
1000 }
1001
1002 wxGridStringTable::~wxGridStringTable()
1003 {
1004 }
1005
1006 long wxGridStringTable::GetNumberRows()
1007 {
1008 return m_data.GetCount();
1009 }
1010
1011 long wxGridStringTable::GetNumberCols()
1012 {
1013 if ( m_data.GetCount() > 0 )
1014 return m_data[0].GetCount();
1015 else
1016 return 0;
1017 }
1018
1019 wxString wxGridStringTable::GetValue( int row, int col )
1020 {
1021 // TODO: bounds checking
1022 //
1023 return m_data[row][col];
1024 }
1025
1026 void wxGridStringTable::SetValue( int row, int col, const wxString& s )
1027 {
1028 // TODO: bounds checking
1029 //
1030 m_data[row][col] = s;
1031 }
1032
1033 bool wxGridStringTable::IsEmptyCell( int row, int col )
1034 {
1035 // TODO: bounds checking
1036 //
1037 return (m_data[row][col] == wxEmptyString);
1038 }
1039
1040
1041 void wxGridStringTable::Clear()
1042 {
1043 int row, col;
1044 int numRows, numCols;
1045
1046 numRows = m_data.GetCount();
1047 if ( numRows > 0 )
1048 {
1049 numCols = m_data[0].GetCount();
1050
1051 for ( row = 0; row < numRows; row++ )
1052 {
1053 for ( col = 0; col < numCols; col++ )
1054 {
1055 m_data[row][col] = wxEmptyString;
1056 }
1057 }
1058 }
1059 }
1060
1061
1062 bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
1063 {
1064 size_t row, col;
1065
1066 size_t curNumRows = m_data.GetCount();
1067 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
1068
1069 if ( pos >= curNumRows )
1070 {
1071 return AppendRows( numRows );
1072 }
1073
1074 wxArrayString sa;
1075 sa.Alloc( curNumCols );
1076 for ( col = 0; col < curNumCols; col++ )
1077 {
1078 sa.Add( wxEmptyString );
1079 }
1080
1081 for ( row = pos; row < pos + numRows; row++ )
1082 {
1083 m_data.Insert( sa, row );
1084 }
1085
1086 if ( GetView() )
1087 {
1088 wxGridTableMessage msg( this,
1089 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
1090 pos,
1091 numRows );
1092
1093 GetView()->ProcessTableMessage( msg );
1094 }
1095
1096 return TRUE;
1097 }
1098
1099 bool wxGridStringTable::AppendRows( size_t numRows )
1100 {
1101 size_t row, col;
1102
1103 size_t curNumRows = m_data.GetCount();
1104 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
1105
1106 wxArrayString sa;
1107 if ( curNumCols > 0 )
1108 {
1109 sa.Alloc( curNumCols );
1110 for ( col = 0; col < curNumCols; col++ )
1111 {
1112 sa.Add( wxEmptyString );
1113 }
1114 }
1115
1116 for ( row = 0; row < numRows; row++ )
1117 {
1118 m_data.Add( sa );
1119 }
1120
1121 if ( GetView() )
1122 {
1123 wxGridTableMessage msg( this,
1124 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
1125 numRows );
1126
1127 GetView()->ProcessTableMessage( msg );
1128 }
1129
1130 return TRUE;
1131 }
1132
1133 bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
1134 {
1135 size_t n;
1136
1137 size_t curNumRows = m_data.GetCount();
1138
1139 if ( pos >= curNumRows )
1140 {
1141 wxString errmsg;
1142 errmsg.Printf("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\n"
1143 "Pos value is invalid for present table with %d rows",
1144 pos, numRows, curNumRows );
1145 wxFAIL_MSG( wxT(errmsg) );
1146 return FALSE;
1147 }
1148
1149 if ( numRows > curNumRows - pos )
1150 {
1151 numRows = curNumRows - pos;
1152 }
1153
1154 if ( numRows >= curNumRows )
1155 {
1156 m_data.Empty(); // don't release memory just yet
1157 }
1158 else
1159 {
1160 for ( n = 0; n < numRows; n++ )
1161 {
1162 m_data.Remove( pos );
1163 }
1164 }
1165
1166 if ( GetView() )
1167 {
1168 wxGridTableMessage msg( this,
1169 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
1170 pos,
1171 numRows );
1172
1173 GetView()->ProcessTableMessage( msg );
1174 }
1175
1176 return TRUE;
1177 }
1178
1179 bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
1180 {
1181 size_t row, col;
1182
1183 size_t curNumRows = m_data.GetCount();
1184 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
1185
1186 if ( pos >= curNumCols )
1187 {
1188 return AppendCols( numCols );
1189 }
1190
1191 for ( row = 0; row < curNumRows; row++ )
1192 {
1193 for ( col = pos; col < pos + numCols; col++ )
1194 {
1195 m_data[row].Insert( wxEmptyString, col );
1196 }
1197 }
1198
1199 if ( GetView() )
1200 {
1201 wxGridTableMessage msg( this,
1202 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
1203 pos,
1204 numCols );
1205
1206 GetView()->ProcessTableMessage( msg );
1207 }
1208
1209 return TRUE;
1210 }
1211
1212 bool wxGridStringTable::AppendCols( size_t numCols )
1213 {
1214 size_t row, n;
1215
1216 size_t curNumRows = m_data.GetCount();
1217 if ( !curNumRows )
1218 {
1219 // TODO: something better than this ?
1220 //
1221 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\n"
1222 "Call AppendRows() first") );
1223 return FALSE;
1224 }
1225
1226 for ( row = 0; row < curNumRows; row++ )
1227 {
1228 for ( n = 0; n < numCols; n++ )
1229 {
1230 m_data[row].Add( wxEmptyString );
1231 }
1232 }
1233
1234 if ( GetView() )
1235 {
1236 wxGridTableMessage msg( this,
1237 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
1238 numCols );
1239
1240 GetView()->ProcessTableMessage( msg );
1241 }
1242
1243 return TRUE;
1244 }
1245
1246 bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
1247 {
1248 size_t row, n;
1249
1250 size_t curNumRows = m_data.GetCount();
1251 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
1252
1253 if ( pos >= curNumCols )
1254 {
1255 wxString errmsg;
1256 errmsg.Printf( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
1257 "Pos value is invalid for present table with %d cols",
1258 pos, numCols, curNumCols );
1259 wxFAIL_MSG( wxT( errmsg ) );
1260 return FALSE;
1261 }
1262
1263 if ( numCols > curNumCols - pos )
1264 {
1265 numCols = curNumCols - pos;
1266 }
1267
1268 for ( row = 0; row < curNumRows; row++ )
1269 {
1270 if ( numCols >= curNumCols )
1271 {
1272 m_data[row].Clear();
1273 }
1274 else
1275 {
1276 for ( n = 0; n < numCols; n++ )
1277 {
1278 m_data[row].Remove( pos );
1279 }
1280 }
1281 }
1282
1283 if ( GetView() )
1284 {
1285 wxGridTableMessage msg( this,
1286 wxGRIDTABLE_NOTIFY_COLS_DELETED,
1287 pos,
1288 numCols );
1289
1290 GetView()->ProcessTableMessage( msg );
1291 }
1292
1293 return TRUE;
1294 }
1295
1296 wxString wxGridStringTable::GetRowLabelValue( int row )
1297 {
1298 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
1299 {
1300 // using default label
1301 //
1302 return wxGridTableBase::GetRowLabelValue( row );
1303 }
1304 else
1305 {
1306 return m_rowLabels[ row ];
1307 }
1308 }
1309
1310 wxString wxGridStringTable::GetColLabelValue( int col )
1311 {
1312 if ( col > (int)(m_colLabels.GetCount()) - 1 )
1313 {
1314 // using default label
1315 //
1316 return wxGridTableBase::GetColLabelValue( col );
1317 }
1318 else
1319 {
1320 return m_colLabels[ col ];
1321 }
1322 }
1323
1324 void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
1325 {
1326 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
1327 {
1328 int n = m_rowLabels.GetCount();
1329 int i;
1330 for ( i = n; i <= row; i++ )
1331 {
1332 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
1333 }
1334 }
1335
1336 m_rowLabels[row] = value;
1337 }
1338
1339 void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
1340 {
1341 if ( col > (int)(m_colLabels.GetCount()) - 1 )
1342 {
1343 int n = m_colLabels.GetCount();
1344 int i;
1345 for ( i = n; i <= col; i++ )
1346 {
1347 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
1348 }
1349 }
1350
1351 m_colLabels[col] = value;
1352 }
1353
1354
1355
1356 //////////////////////////////////////////////////////////////////////
1357
1358 IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl, wxTextCtrl )
1359
1360 BEGIN_EVENT_TABLE( wxGridTextCtrl, wxTextCtrl )
1361 EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown )
1362 END_EVENT_TABLE()
1363
1364
1365 wxGridTextCtrl::wxGridTextCtrl( wxWindow *par,
1366 wxGrid *grid,
1367 bool isCellControl,
1368 wxWindowID id,
1369 const wxString& value,
1370 const wxPoint& pos,
1371 const wxSize& size,
1372 long style )
1373 : wxTextCtrl( par, id, value, pos, size, style )
1374 {
1375 m_grid = grid;
1376 m_isCellControl = isCellControl;
1377 }
1378
1379
1380 void wxGridTextCtrl::OnKeyDown( wxKeyEvent& event )
1381 {
1382 switch ( event.KeyCode() )
1383 {
1384 #if 0
1385 case WXK_ESCAPE:
1386 m_grid->SetEditControlValue( startValue );
1387 SetInsertionPointEnd();
1388 break;
1389 #else
1390 case WXK_ESCAPE:
1391 m_grid->EnableCellEditControl( FALSE );
1392 #endif
1393 case WXK_UP:
1394 case WXK_DOWN:
1395 case WXK_LEFT:
1396 case WXK_RIGHT:
1397 case WXK_PRIOR:
1398 case WXK_NEXT:
1399 case WXK_SPACE:
1400 if ( m_isCellControl )
1401 {
1402 // send the event to the parent grid, skipping the
1403 // event if nothing happens
1404 //
1405 event.Skip( m_grid->ProcessEvent( event ) );
1406 }
1407 else
1408 {
1409 // default text control response within the top edit
1410 // control
1411 //
1412 event.Skip();
1413 }
1414 break;
1415
1416 case WXK_RETURN:
1417 if ( m_isCellControl )
1418 {
1419 if ( !m_grid->ProcessEvent( event ) )
1420 {
1421 #if defined(__WXMOTIF__) || defined(__WXGTK__)
1422 // wxMotif needs a little extra help...
1423 //
1424 int pos = GetInsertionPoint();
1425 wxString s( GetValue() );
1426 s = s.Left(pos) + "\n" + s.Mid(pos);
1427 SetValue(s);
1428 SetInsertionPoint( pos );
1429 #else
1430 // the other ports can handle a Return key press
1431 //
1432 event.Skip();
1433 #endif
1434 }
1435 }
1436 break;
1437 case WXK_HOME:
1438 case WXK_END:
1439 if ( m_isCellControl )
1440 {
1441 // send the event to the parent grid, skipping the
1442 // event if nothing happens
1443 //
1444 event.Skip( m_grid->ProcessEvent( event ) );
1445 }
1446 else
1447 {
1448 // default text control response within the top edit
1449 // control
1450 //
1451 event.Skip();
1452 }
1453 break;
1454
1455 default:
1456 event.Skip();
1457 }
1458 }
1459
1460 void wxGridTextCtrl::SetStartValue( const wxString& s )
1461 {
1462 startValue = s;
1463 wxTextCtrl::SetValue(s);
1464 }
1465
1466
1467
1468 //////////////////////////////////////////////////////////////////////
1469
1470 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
1471
1472 BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
1473 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
1474 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
1475 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
1476 END_EVENT_TABLE()
1477
1478 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
1479 wxWindowID id,
1480 const wxPoint &pos, const wxSize &size )
1481 : wxWindow( parent, id, pos, size )
1482 {
1483 m_owner = parent;
1484 }
1485
1486 void wxGridRowLabelWindow::OnPaint( wxPaintEvent &event )
1487 {
1488 wxPaintDC dc(this);
1489
1490 // NO - don't do this because it will set both the x and y origin
1491 // coords to match the parent scrolled window and we just want to
1492 // set the y coord - MB
1493 //
1494 // m_owner->PrepareDC( dc );
1495
1496 int x, y;
1497 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
1498 dc.SetDeviceOrigin( 0, -y );
1499
1500 m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
1501 m_owner->DrawRowLabels( dc );
1502 }
1503
1504
1505 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
1506 {
1507 m_owner->ProcessRowLabelMouseEvent( event );
1508 }
1509
1510
1511 // This seems to be required for wxMotif otherwise the mouse
1512 // cursor must be in the cell edit control to get key events
1513 //
1514 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
1515 {
1516 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1517 }
1518
1519
1520
1521 //////////////////////////////////////////////////////////////////////
1522
1523 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
1524
1525 BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
1526 EVT_PAINT( wxGridColLabelWindow::OnPaint )
1527 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
1528 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
1529 END_EVENT_TABLE()
1530
1531 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
1532 wxWindowID id,
1533 const wxPoint &pos, const wxSize &size )
1534 : wxWindow( parent, id, pos, size )
1535 {
1536 m_owner = parent;
1537 }
1538
1539 void wxGridColLabelWindow::OnPaint( wxPaintEvent &event )
1540 {
1541 wxPaintDC dc(this);
1542
1543 // NO - don't do this because it will set both the x and y origin
1544 // coords to match the parent scrolled window and we just want to
1545 // set the x coord - MB
1546 //
1547 // m_owner->PrepareDC( dc );
1548
1549 int x, y;
1550 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
1551 dc.SetDeviceOrigin( -x, 0 );
1552
1553 m_owner->CalcColLabelsExposed( GetUpdateRegion() );
1554 m_owner->DrawColLabels( dc );
1555 }
1556
1557
1558 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
1559 {
1560 m_owner->ProcessColLabelMouseEvent( event );
1561 }
1562
1563
1564 // This seems to be required for wxMotif otherwise the mouse
1565 // cursor must be in the cell edit control to get key events
1566 //
1567 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
1568 {
1569 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1570 }
1571
1572
1573
1574 //////////////////////////////////////////////////////////////////////
1575
1576 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
1577
1578 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
1579 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
1580 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
1581 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
1582 END_EVENT_TABLE()
1583
1584 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
1585 wxWindowID id,
1586 const wxPoint &pos, const wxSize &size )
1587 : wxWindow( parent, id, pos, size )
1588 {
1589 m_owner = parent;
1590 }
1591
1592 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
1593 {
1594 wxPaintDC dc(this);
1595
1596 int client_height = 0;
1597 int client_width = 0;
1598 GetClientSize( &client_width, &client_height );
1599
1600 dc.SetPen( *wxBLACK_PEN );
1601 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
1602 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
1603
1604 dc.SetPen( *wxWHITE_PEN );
1605 dc.DrawLine( 0, 0, client_width, 0 );
1606 dc.DrawLine( 0, 0, 0, client_height );
1607 }
1608
1609
1610 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
1611 {
1612 m_owner->ProcessCornerLabelMouseEvent( event );
1613 }
1614
1615
1616 // This seems to be required for wxMotif otherwise the mouse
1617 // cursor must be in the cell edit control to get key events
1618 //
1619 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
1620 {
1621 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1622 }
1623
1624
1625
1626 //////////////////////////////////////////////////////////////////////
1627
1628 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
1629
1630 BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
1631 EVT_PAINT( wxGridWindow::OnPaint )
1632 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
1633 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
1634 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
1635 END_EVENT_TABLE()
1636
1637 wxGridWindow::wxGridWindow( wxGrid *parent,
1638 wxGridRowLabelWindow *rowLblWin,
1639 wxGridColLabelWindow *colLblWin,
1640 wxWindowID id, const wxPoint &pos, const wxSize &size )
1641 : wxPanel( parent, id, pos, size, 0, "grid window" )
1642 {
1643 m_owner = parent;
1644 m_rowLabelWin = rowLblWin;
1645 m_colLabelWin = colLblWin;
1646 SetBackgroundColour( "WHITE" );
1647 }
1648
1649
1650 wxGridWindow::~wxGridWindow()
1651 {
1652 }
1653
1654
1655 void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1656 {
1657 wxPaintDC dc( this );
1658 m_owner->PrepareDC( dc );
1659 wxRegion reg = GetUpdateRegion();
1660 m_owner->CalcCellsExposed( reg );
1661 m_owner->DrawGridCellArea( dc );
1662 #if WXGRID_DRAW_LINES
1663 m_owner->DrawAllGridLines( dc, reg );
1664 #endif
1665 }
1666
1667
1668 void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1669 {
1670 wxPanel::ScrollWindow( dx, dy, rect );
1671 m_rowLabelWin->ScrollWindow( 0, dy, rect );
1672 m_colLabelWin->ScrollWindow( dx, 0, rect );
1673 }
1674
1675
1676 void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
1677 {
1678 m_owner->ProcessGridCellMouseEvent( event );
1679 }
1680
1681
1682 // This seems to be required for wxMotif otherwise the mouse
1683 // cursor must be in the cell edit control to get key events
1684 //
1685 void wxGridWindow::OnKeyDown( wxKeyEvent& event )
1686 {
1687 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1688 }
1689
1690 void wxGridWindow::OnEraseBackground(wxEraseEvent&)
1691 { }
1692
1693
1694
1695
1696 //////////////////////////////////////////////////////////////////////
1697
1698 #define ID_EDIT_TIMER 1001
1699
1700 IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
1701
1702 BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
1703 EVT_PAINT( wxGrid::OnPaint )
1704 EVT_SIZE( wxGrid::OnSize )
1705 EVT_KEY_DOWN( wxGrid::OnKeyDown )
1706 EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground )
1707 EVT_TIMER( ID_EDIT_TIMER, wxGrid::OnEditTimer )
1708 END_EVENT_TABLE()
1709
1710 wxGrid::wxGrid( wxWindow *parent,
1711 wxWindowID id,
1712 const wxPoint& pos,
1713 const wxSize& size,
1714 long style,
1715 const wxString& name )
1716 : wxScrolledWindow( parent, id, pos, size, style, name )
1717 {
1718 Create();
1719 }
1720
1721
1722 wxGrid::~wxGrid()
1723 {
1724 ClearAttrCache();
1725 m_defaultCellAttr->SafeDecRef();
1726
1727 #ifdef DEBUG_ATTR_CACHE
1728 size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
1729 wxPrintf(_T("wxGrid attribute cache statistics: "
1730 "total: %u, hits: %u (%u%%)\n"),
1731 total, gs_nAttrCacheHits,
1732 total ? (gs_nAttrCacheHits*100) / total : 0);
1733 #endif
1734
1735 if (m_ownTable)
1736 delete m_table;
1737 delete m_editTimer;
1738 }
1739
1740
1741 //
1742 // ----- internal init and update functions
1743 //
1744
1745 void wxGrid::Create()
1746 {
1747 m_created = FALSE; // set to TRUE by CreateGrid
1748 m_displayed = FALSE; // set to TRUE by OnPaint
1749
1750 m_table = (wxGridTableBase *) NULL;
1751 m_ownTable = FALSE;
1752
1753 m_cellEditCtrlEnabled = FALSE;
1754
1755 m_defaultCellAttr = new wxGridCellAttr;
1756 m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
1757 // RD: Should we fill the default attrs now or is waiting until Init() okay?
1758
1759
1760 m_numRows = 0;
1761 m_numCols = 0;
1762 m_currentCellCoords = wxGridNoCellCoords;
1763
1764 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
1765 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
1766
1767 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
1768 -1,
1769 wxDefaultPosition,
1770 wxDefaultSize );
1771
1772 m_rowLabelWin = new wxGridRowLabelWindow( this,
1773 -1,
1774 wxDefaultPosition,
1775 wxDefaultSize );
1776
1777 m_colLabelWin = new wxGridColLabelWindow( this,
1778 -1,
1779 wxDefaultPosition,
1780 wxDefaultSize );
1781
1782 m_gridWin = new wxGridWindow( this,
1783 m_rowLabelWin,
1784 m_colLabelWin,
1785 -1,
1786 wxDefaultPosition,
1787 wxDefaultSize );
1788
1789 SetTargetWindow( m_gridWin );
1790 }
1791
1792
1793 bool wxGrid::CreateGrid( int numRows, int numCols )
1794 {
1795 if ( m_created )
1796 {
1797 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
1798 return FALSE;
1799 }
1800 else
1801 {
1802 m_numRows = numRows;
1803 m_numCols = numCols;
1804
1805 m_table = new wxGridStringTable( m_numRows, m_numCols );
1806 m_table->SetView( this );
1807 m_ownTable = TRUE;
1808 Init();
1809 m_created = TRUE;
1810 }
1811
1812 return m_created;
1813 }
1814
1815 bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership )
1816 {
1817 if ( m_created )
1818 {
1819 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
1820 return FALSE;
1821 }
1822 else
1823 {
1824 m_numRows = table->GetNumberRows();
1825 m_numCols = table->GetNumberCols();
1826
1827 m_table = table;
1828 m_table->SetView( this );
1829 if (takeOwnership)
1830 m_ownTable = TRUE;
1831 Init();
1832 m_created = TRUE;
1833 }
1834
1835 return m_created;
1836 }
1837
1838
1839 void wxGrid::Init()
1840 {
1841 int i;
1842
1843 if ( m_numRows <= 0 )
1844 m_numRows = WXGRID_DEFAULT_NUMBER_ROWS;
1845
1846 if ( m_numCols <= 0 )
1847 m_numCols = WXGRID_DEFAULT_NUMBER_COLS;
1848
1849 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
1850 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
1851
1852 if ( m_rowLabelWin )
1853 {
1854 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
1855 }
1856 else
1857 {
1858 m_labelBackgroundColour = wxColour( _T("WHITE") );
1859 }
1860
1861 m_labelTextColour = wxColour( _T("BLACK") );
1862
1863 // init attr cache
1864 m_attrCache.row = -1;
1865
1866 // TODO: something better than this ?
1867 //
1868 m_labelFont = this->GetFont();
1869 m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 );
1870
1871 m_rowLabelHorizAlign = wxLEFT;
1872 m_rowLabelVertAlign = wxCENTRE;
1873
1874 m_colLabelHorizAlign = wxCENTRE;
1875 m_colLabelVertAlign = wxTOP;
1876
1877 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
1878 m_defaultRowHeight = m_gridWin->GetCharHeight();
1879
1880 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
1881 m_defaultRowHeight += 8;
1882 #else
1883 m_defaultRowHeight += 4;
1884 #endif
1885
1886 m_rowHeights.Alloc( m_numRows );
1887 m_rowBottoms.Alloc( m_numRows );
1888 int rowBottom = 0;
1889 for ( i = 0; i < m_numRows; i++ )
1890 {
1891 m_rowHeights.Add( m_defaultRowHeight );
1892 rowBottom += m_defaultRowHeight;
1893 m_rowBottoms.Add( rowBottom );
1894 }
1895
1896 m_colWidths.Alloc( m_numCols );
1897 m_colRights.Alloc( m_numCols );
1898 int colRight = 0;
1899 for ( i = 0; i < m_numCols; i++ )
1900 {
1901 m_colWidths.Add( m_defaultColWidth );
1902 colRight += m_defaultColWidth;
1903 m_colRights.Add( colRight );
1904 }
1905
1906 // Set default cell attributes
1907 m_defaultCellAttr->SetFont(GetFont());
1908 m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP);
1909 m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
1910 m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
1911 m_defaultCellAttr->SetTextColour(
1912 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
1913 m_defaultCellAttr->SetBackgroundColour(
1914 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
1915
1916
1917 m_gridLineColour = wxColour( 128, 128, 255 );
1918 m_gridLinesEnabled = TRUE;
1919
1920 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1921 m_winCapture = (wxWindow *)NULL;
1922 m_dragLastPos = -1;
1923 m_dragRowOrCol = -1;
1924 m_isDragging = FALSE;
1925 m_startDragPos = wxDefaultPosition;
1926
1927 m_editTimer = new wxTimer( this, ID_EDIT_TIMER );
1928 m_waitForSlowClick = FALSE;
1929
1930 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
1931 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
1932
1933 m_currentCellCoords = wxGridNoCellCoords;
1934
1935 m_selectedTopLeft = wxGridNoCellCoords;
1936 m_selectedBottomRight = wxGridNoCellCoords;
1937 m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT);
1938 m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
1939
1940 m_editable = TRUE; // default for whole grid
1941
1942 m_inOnKeyDown = FALSE;
1943 m_batchCount = 0;
1944
1945 }
1946
1947
1948 void wxGrid::CalcDimensions()
1949 {
1950 int cw, ch;
1951 GetClientSize( &cw, &ch );
1952
1953 if ( m_numRows > 0 && m_numCols > 0 )
1954 {
1955 int right = m_colRights[ m_numCols-1 ] + 50;
1956 int bottom = m_rowBottoms[ m_numRows-1 ] + 50;
1957
1958 // TODO: restore the scroll position that we had before sizing
1959 //
1960 int x, y;
1961 GetViewStart( &x, &y );
1962 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
1963 right/GRID_SCROLL_LINE, bottom/GRID_SCROLL_LINE,
1964 x, y );
1965 }
1966 }
1967
1968
1969 void wxGrid::CalcWindowSizes()
1970 {
1971 int cw, ch;
1972 GetClientSize( &cw, &ch );
1973
1974 if ( m_cornerLabelWin->IsShown() )
1975 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
1976
1977 if ( m_colLabelWin->IsShown() )
1978 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
1979
1980 if ( m_rowLabelWin->IsShown() )
1981 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
1982
1983 if ( m_gridWin->IsShown() )
1984 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
1985 }
1986
1987
1988 // this is called when the grid table sends a message to say that it
1989 // has been redimensioned
1990 //
1991 bool wxGrid::Redimension( wxGridTableMessage& msg )
1992 {
1993 int i;
1994
1995 switch ( msg.GetId() )
1996 {
1997 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
1998 {
1999 size_t pos = msg.GetCommandInt();
2000 int numRows = msg.GetCommandInt2();
2001 for ( i = 0; i < numRows; i++ )
2002 {
2003 m_rowHeights.Insert( m_defaultRowHeight, pos );
2004 m_rowBottoms.Insert( 0, pos );
2005 }
2006 m_numRows += numRows;
2007
2008 int bottom = 0;
2009 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
2010
2011 for ( i = pos; i < m_numRows; i++ )
2012 {
2013 bottom += m_rowHeights[i];
2014 m_rowBottoms[i] = bottom;
2015 }
2016 CalcDimensions();
2017 }
2018 return TRUE;
2019
2020 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
2021 {
2022 int numRows = msg.GetCommandInt();
2023 for ( i = 0; i < numRows; i++ )
2024 {
2025 m_rowHeights.Add( m_defaultRowHeight );
2026 m_rowBottoms.Add( 0 );
2027 }
2028
2029 int oldNumRows = m_numRows;
2030 m_numRows += numRows;
2031
2032 int bottom = 0;
2033 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
2034
2035 for ( i = oldNumRows; i < m_numRows; i++ )
2036 {
2037 bottom += m_rowHeights[i];
2038 m_rowBottoms[i] = bottom;
2039 }
2040 CalcDimensions();
2041 }
2042 return TRUE;
2043
2044 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
2045 {
2046 size_t pos = msg.GetCommandInt();
2047 int numRows = msg.GetCommandInt2();
2048 for ( i = 0; i < numRows; i++ )
2049 {
2050 m_rowHeights.Remove( pos );
2051 m_rowBottoms.Remove( pos );
2052 }
2053 m_numRows -= numRows;
2054
2055 if ( !m_numRows )
2056 {
2057 m_numCols = 0;
2058 m_colWidths.Clear();
2059 m_colRights.Clear();
2060 m_currentCellCoords = wxGridNoCellCoords;
2061 }
2062 else
2063 {
2064 if ( m_currentCellCoords.GetRow() >= m_numRows )
2065 m_currentCellCoords.Set( 0, 0 );
2066
2067 int h = 0;
2068 for ( i = 0; i < m_numRows; i++ )
2069 {
2070 h += m_rowHeights[i];
2071 m_rowBottoms[i] = h;
2072 }
2073 }
2074
2075 CalcDimensions();
2076 }
2077 return TRUE;
2078
2079 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
2080 {
2081 size_t pos = msg.GetCommandInt();
2082 int numCols = msg.GetCommandInt2();
2083 for ( i = 0; i < numCols; i++ )
2084 {
2085 m_colWidths.Insert( m_defaultColWidth, pos );
2086 m_colRights.Insert( 0, pos );
2087 }
2088 m_numCols += numCols;
2089
2090 int right = 0;
2091 if ( pos > 0 ) right = m_colRights[pos-1];
2092
2093 for ( i = pos; i < m_numCols; i++ )
2094 {
2095 right += m_colWidths[i];
2096 m_colRights[i] = right;
2097 }
2098 CalcDimensions();
2099 }
2100 return TRUE;
2101
2102 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
2103 {
2104 int numCols = msg.GetCommandInt();
2105 for ( i = 0; i < numCols; i++ )
2106 {
2107 m_colWidths.Add( m_defaultColWidth );
2108 m_colRights.Add( 0 );
2109 }
2110
2111 int oldNumCols = m_numCols;
2112 m_numCols += numCols;
2113
2114 int right = 0;
2115 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
2116
2117 for ( i = oldNumCols; i < m_numCols; i++ )
2118 {
2119 right += m_colWidths[i];
2120 m_colRights[i] = right;
2121 }
2122 CalcDimensions();
2123 }
2124 return TRUE;
2125
2126 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
2127 {
2128 size_t pos = msg.GetCommandInt();
2129 int numCols = msg.GetCommandInt2();
2130 for ( i = 0; i < numCols; i++ )
2131 {
2132 m_colWidths.Remove( pos );
2133 m_colRights.Remove( pos );
2134 }
2135 m_numCols -= numCols;
2136
2137 if ( !m_numCols )
2138 {
2139 #if 0 // leave the row alone here so that AppendCols will work subsequently
2140 m_numRows = 0;
2141 m_rowHeights.Clear();
2142 m_rowBottoms.Clear();
2143 #endif
2144 m_currentCellCoords = wxGridNoCellCoords;
2145 }
2146 else
2147 {
2148 if ( m_currentCellCoords.GetCol() >= m_numCols )
2149 m_currentCellCoords.Set( 0, 0 );
2150
2151 int w = 0;
2152 for ( i = 0; i < m_numCols; i++ )
2153 {
2154 w += m_colWidths[i];
2155 m_colRights[i] = w;
2156 }
2157 }
2158 CalcDimensions();
2159 }
2160 return TRUE;
2161 }
2162
2163 return FALSE;
2164 }
2165
2166
2167 void wxGrid::CalcRowLabelsExposed( wxRegion& reg )
2168 {
2169 wxRegionIterator iter( reg );
2170 wxRect r;
2171
2172 m_rowLabelsExposed.Empty();
2173
2174 int top, bottom;
2175 while ( iter )
2176 {
2177 r = iter.GetRect();
2178
2179 // TODO: remove this when we can...
2180 // There is a bug in wxMotif that gives garbage update
2181 // rectangles if you jump-scroll a long way by clicking the
2182 // scrollbar with middle button. This is a work-around
2183 //
2184 #if defined(__WXMOTIF__)
2185 int cw, ch;
2186 m_gridWin->GetClientSize( &cw, &ch );
2187 if ( r.GetTop() > ch ) r.SetTop( 0 );
2188 r.SetBottom( wxMin( r.GetBottom(), ch ) );
2189 #endif
2190
2191 // logical bounds of update region
2192 //
2193 int dummy;
2194 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
2195 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
2196
2197 // find the row labels within these bounds
2198 //
2199 int row;
2200 int rowTop;
2201 for ( row = 0; row < m_numRows; row++ )
2202 {
2203 if ( m_rowBottoms[row] < top ) continue;
2204
2205 rowTop = m_rowBottoms[row] - m_rowHeights[row];
2206 if ( rowTop > bottom ) break;
2207
2208 m_rowLabelsExposed.Add( row );
2209 }
2210
2211 iter++ ;
2212 }
2213 }
2214
2215
2216 void wxGrid::CalcColLabelsExposed( wxRegion& reg )
2217 {
2218 wxRegionIterator iter( reg );
2219 wxRect r;
2220
2221 m_colLabelsExposed.Empty();
2222
2223 int left, right;
2224 while ( iter )
2225 {
2226 r = iter.GetRect();
2227
2228 // TODO: remove this when we can...
2229 // There is a bug in wxMotif that gives garbage update
2230 // rectangles if you jump-scroll a long way by clicking the
2231 // scrollbar with middle button. This is a work-around
2232 //
2233 #if defined(__WXMOTIF__)
2234 int cw, ch;
2235 m_gridWin->GetClientSize( &cw, &ch );
2236 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
2237 r.SetRight( wxMin( r.GetRight(), cw ) );
2238 #endif
2239
2240 // logical bounds of update region
2241 //
2242 int dummy;
2243 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
2244 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
2245
2246 // find the cells within these bounds
2247 //
2248 int col;
2249 int colLeft;
2250 for ( col = 0; col < m_numCols; col++ )
2251 {
2252 if ( m_colRights[col] < left ) continue;
2253
2254 colLeft = m_colRights[col] - m_colWidths[col];
2255 if ( colLeft > right ) break;
2256
2257 m_colLabelsExposed.Add( col );
2258 }
2259
2260 iter++ ;
2261 }
2262 }
2263
2264
2265 void wxGrid::CalcCellsExposed( wxRegion& reg )
2266 {
2267 wxRegionIterator iter( reg );
2268 wxRect r;
2269
2270 m_cellsExposed.Empty();
2271 m_rowsExposed.Empty();
2272 m_colsExposed.Empty();
2273
2274 int left, top, right, bottom;
2275 while ( iter )
2276 {
2277 r = iter.GetRect();
2278
2279 // TODO: remove this when we can...
2280 // There is a bug in wxMotif that gives garbage update
2281 // rectangles if you jump-scroll a long way by clicking the
2282 // scrollbar with middle button. This is a work-around
2283 //
2284 #if defined(__WXMOTIF__)
2285 int cw, ch;
2286 m_gridWin->GetClientSize( &cw, &ch );
2287 if ( r.GetTop() > ch ) r.SetTop( 0 );
2288 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
2289 r.SetRight( wxMin( r.GetRight(), cw ) );
2290 r.SetBottom( wxMin( r.GetBottom(), ch ) );
2291 #endif
2292
2293 // logical bounds of update region
2294 //
2295 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
2296 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
2297
2298 // find the cells within these bounds
2299 //
2300 int row, col;
2301 int colLeft, rowTop;
2302 for ( row = 0; row < m_numRows; row++ )
2303 {
2304 if ( m_rowBottoms[row] < top ) continue;
2305
2306 rowTop = m_rowBottoms[row] - m_rowHeights[row];
2307 if ( rowTop > bottom ) break;
2308
2309 m_rowsExposed.Add( row );
2310
2311 for ( col = 0; col < m_numCols; col++ )
2312 {
2313 if ( m_colRights[col] < left ) continue;
2314
2315 colLeft = m_colRights[col] - m_colWidths[col];
2316 if ( colLeft > right ) break;
2317
2318 if ( m_colsExposed.Index( col ) == wxNOT_FOUND ) m_colsExposed.Add( col );
2319 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
2320 }
2321 }
2322
2323 iter++ ;
2324 }
2325 }
2326
2327
2328 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
2329 {
2330 int x, y, row;
2331 wxPoint pos( event.GetPosition() );
2332 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
2333
2334 if ( event.Dragging() )
2335 {
2336 m_isDragging = TRUE;
2337
2338 if ( event.LeftIsDown() )
2339 {
2340 switch( m_cursorMode )
2341 {
2342 case WXGRID_CURSOR_RESIZE_ROW:
2343 {
2344 int cw, ch, left, dummy;
2345 m_gridWin->GetClientSize( &cw, &ch );
2346 CalcUnscrolledPosition( 0, 0, &left, &dummy );
2347
2348 wxClientDC dc( m_gridWin );
2349 PrepareDC( dc );
2350 y = wxMax( y,
2351 m_rowBottoms[m_dragRowOrCol] -
2352 m_rowHeights[m_dragRowOrCol] +
2353 WXGRID_MIN_ROW_HEIGHT );
2354 dc.SetLogicalFunction(wxINVERT);
2355 if ( m_dragLastPos >= 0 )
2356 {
2357 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
2358 }
2359 dc.DrawLine( left, y, left+cw, y );
2360 m_dragLastPos = y;
2361 }
2362 break;
2363
2364 case WXGRID_CURSOR_SELECT_ROW:
2365 if ( (row = YToRow( y )) >= 0 &&
2366 !IsInSelection( row, 0 ) )
2367 {
2368 SelectRow( row, TRUE );
2369 }
2370
2371 // default label to suppress warnings about "enumeration value
2372 // 'xxx' not handled in switch
2373 default:
2374 break;
2375 }
2376 }
2377 return;
2378 }
2379
2380 m_isDragging = FALSE;
2381
2382
2383 // ------------ Entering or leaving the window
2384 //
2385 if ( event.Entering() || event.Leaving() )
2386 {
2387 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
2388 }
2389
2390
2391 // ------------ Left button pressed
2392 //
2393 else if ( event.LeftDown() )
2394 {
2395 // don't send a label click event for a hit on the
2396 // edge of the row label - this is probably the user
2397 // wanting to resize the row
2398 //
2399 if ( YToEdgeOfRow(y) < 0 )
2400 {
2401 row = YToRow(y);
2402 if ( row >= 0 &&
2403 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
2404 {
2405 SelectRow( row, event.ShiftDown() );
2406 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
2407 }
2408 }
2409 else
2410 {
2411 // starting to drag-resize a row
2412 //
2413 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
2414 }
2415 }
2416
2417
2418 // ------------ Left double click
2419 //
2420 else if (event.LeftDClick() )
2421 {
2422 if ( YToEdgeOfRow(y) < 0 )
2423 {
2424 row = YToRow(y);
2425 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
2426 }
2427 }
2428
2429
2430 // ------------ Left button released
2431 //
2432 else if ( event.LeftUp() )
2433 {
2434 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2435 {
2436 DoEndDragResizeRow();
2437
2438 // Note: we are ending the event *after* doing
2439 // default processing in this case
2440 //
2441 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
2442 }
2443
2444 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
2445 m_dragLastPos = -1;
2446 }
2447
2448
2449 // ------------ Right button down
2450 //
2451 else if ( event.RightDown() )
2452 {
2453 row = YToRow(y);
2454 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
2455 {
2456 // no default action at the moment
2457 }
2458 }
2459
2460
2461 // ------------ Right double click
2462 //
2463 else if ( event.RightDClick() )
2464 {
2465 row = YToRow(y);
2466 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
2467 {
2468 // no default action at the moment
2469 }
2470 }
2471
2472
2473 // ------------ No buttons down and mouse moving
2474 //
2475 else if ( event.Moving() )
2476 {
2477 m_dragRowOrCol = YToEdgeOfRow( y );
2478 if ( m_dragRowOrCol >= 0 )
2479 {
2480 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2481 {
2482 // don't capture the mouse yet
2483 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
2484 }
2485 }
2486 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2487 {
2488 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
2489 }
2490 }
2491 }
2492
2493
2494 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
2495 {
2496 int x, y, col;
2497 wxPoint pos( event.GetPosition() );
2498 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
2499
2500 if ( event.Dragging() )
2501 {
2502 m_isDragging = TRUE;
2503
2504 if ( event.LeftIsDown() )
2505 {
2506 switch( m_cursorMode )
2507 {
2508 case WXGRID_CURSOR_RESIZE_COL:
2509 {
2510 int cw, ch, dummy, top;
2511 m_gridWin->GetClientSize( &cw, &ch );
2512 CalcUnscrolledPosition( 0, 0, &dummy, &top );
2513
2514 wxClientDC dc( m_gridWin );
2515 PrepareDC( dc );
2516 x = wxMax( x,
2517 m_colRights[m_dragRowOrCol] -
2518 m_colWidths[m_dragRowOrCol] +
2519 WXGRID_MIN_COL_WIDTH );
2520 dc.SetLogicalFunction(wxINVERT);
2521 if ( m_dragLastPos >= 0 )
2522 {
2523 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
2524 }
2525 dc.DrawLine( x, top, x, top+ch );
2526 m_dragLastPos = x;
2527 }
2528 break;
2529
2530 case WXGRID_CURSOR_SELECT_COL:
2531 if ( (col = XToCol( x )) >= 0 &&
2532 !IsInSelection( 0, col ) )
2533 {
2534 SelectCol( col, TRUE );
2535 }
2536
2537 // default label to suppress warnings about "enumeration value
2538 // 'xxx' not handled in switch
2539 default:
2540 break;
2541 }
2542 }
2543 return;
2544 }
2545
2546 m_isDragging = FALSE;
2547
2548
2549 // ------------ Entering or leaving the window
2550 //
2551 if ( event.Entering() || event.Leaving() )
2552 {
2553 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
2554 }
2555
2556
2557 // ------------ Left button pressed
2558 //
2559 else if ( event.LeftDown() )
2560 {
2561 // don't send a label click event for a hit on the
2562 // edge of the col label - this is probably the user
2563 // wanting to resize the col
2564 //
2565 if ( XToEdgeOfCol(x) < 0 )
2566 {
2567 col = XToCol(x);
2568 if ( col >= 0 &&
2569 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
2570 {
2571 SelectCol( col, event.ShiftDown() );
2572 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
2573 }
2574 }
2575 else
2576 {
2577 // starting to drag-resize a col
2578 //
2579 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
2580 }
2581 }
2582
2583
2584 // ------------ Left double click
2585 //
2586 if ( event.LeftDClick() )
2587 {
2588 if ( XToEdgeOfCol(x) < 0 )
2589 {
2590 col = XToCol(x);
2591 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
2592 }
2593 }
2594
2595
2596 // ------------ Left button released
2597 //
2598 else if ( event.LeftUp() )
2599 {
2600 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2601 {
2602 DoEndDragResizeCol();
2603
2604 // Note: we are ending the event *after* doing
2605 // default processing in this case
2606 //
2607 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2608 }
2609
2610 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
2611 m_dragLastPos = -1;
2612 }
2613
2614
2615 // ------------ Right button down
2616 //
2617 else if ( event.RightDown() )
2618 {
2619 col = XToCol(x);
2620 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
2621 {
2622 // no default action at the moment
2623 }
2624 }
2625
2626
2627 // ------------ Right double click
2628 //
2629 else if ( event.RightDClick() )
2630 {
2631 col = XToCol(x);
2632 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
2633 {
2634 // no default action at the moment
2635 }
2636 }
2637
2638
2639 // ------------ No buttons down and mouse moving
2640 //
2641 else if ( event.Moving() )
2642 {
2643 m_dragRowOrCol = XToEdgeOfCol( x );
2644 if ( m_dragRowOrCol >= 0 )
2645 {
2646 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2647 {
2648 // don't capture the cursor yet
2649 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
2650 }
2651 }
2652 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2653 {
2654 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
2655 }
2656 }
2657 }
2658
2659
2660 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
2661 {
2662 if ( event.LeftDown() )
2663 {
2664 // indicate corner label by having both row and
2665 // col args == -1
2666 //
2667 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
2668 {
2669 SelectAll();
2670 }
2671 }
2672
2673 else if ( event.LeftDClick() )
2674 {
2675 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
2676 }
2677
2678 else if ( event.RightDown() )
2679 {
2680 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
2681 {
2682 // no default action at the moment
2683 }
2684 }
2685
2686 else if ( event.RightDClick() )
2687 {
2688 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
2689 {
2690 // no default action at the moment
2691 }
2692 }
2693 }
2694
2695 void wxGrid::ChangeCursorMode(CursorMode mode,
2696 wxWindow *win,
2697 bool captureMouse)
2698 {
2699 #ifdef __WXDEBUG__
2700 static const wxChar *cursorModes[] =
2701 {
2702 _T("SELECT_CELL"),
2703 _T("RESIZE_ROW"),
2704 _T("RESIZE_COL"),
2705 _T("SELECT_ROW"),
2706 _T("SELECT_COL")
2707 };
2708
2709 wxLogTrace(_T("grid"),
2710 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
2711 win == m_colLabelWin ? _T("colLabelWin")
2712 : win ? _T("rowLabelWin")
2713 : _T("gridWin"),
2714 cursorModes[m_cursorMode], cursorModes[mode]);
2715 #endif // __WXDEBUG__
2716
2717 if ( mode == m_cursorMode )
2718 return;
2719
2720 if ( !win )
2721 {
2722 // by default use the grid itself
2723 win = m_gridWin;
2724 }
2725
2726 if ( m_winCapture )
2727 {
2728 m_winCapture->ReleaseMouse();
2729 m_winCapture = (wxWindow *)NULL;
2730 }
2731
2732 m_cursorMode = mode;
2733
2734 switch ( m_cursorMode )
2735 {
2736 case WXGRID_CURSOR_RESIZE_ROW:
2737 win->SetCursor( m_rowResizeCursor );
2738 break;
2739
2740 case WXGRID_CURSOR_RESIZE_COL:
2741 win->SetCursor( m_colResizeCursor );
2742 break;
2743
2744 default:
2745 win->SetCursor( *wxSTANDARD_CURSOR );
2746 }
2747
2748 // we need to capture mouse when resizing
2749 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
2750 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
2751
2752 if ( captureMouse && resize )
2753 {
2754 win->CaptureMouse();
2755 m_winCapture = win;
2756 }
2757 }
2758
2759 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
2760 {
2761 int x, y;
2762 wxPoint pos( event.GetPosition() );
2763 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
2764
2765 wxGridCellCoords coords;
2766 XYToCell( x, y, coords );
2767
2768 if ( event.Dragging() )
2769 {
2770 //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
2771
2772 // Don't start doing anything until the mouse has been drug at
2773 // least 3 pixels in any direction...
2774 if (! m_isDragging) {
2775 if (m_startDragPos == wxDefaultPosition) {
2776 m_startDragPos = pos;
2777 return;
2778 }
2779 if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
2780 return;
2781 }
2782
2783 m_isDragging = TRUE;
2784 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2785 {
2786 // Hide the edit control, so it
2787 // won't interfer with drag-shrinking.
2788 if ( IsCellEditControlEnabled() )
2789 HideCellEditControl();
2790
2791 // Have we captured the mouse yet?
2792 if (! m_winCapture) {
2793 m_winCapture = m_gridWin;
2794 m_winCapture->CaptureMouse();
2795 }
2796
2797 if ( coords != wxGridNoCellCoords )
2798 {
2799 if ( !IsSelection() )
2800 {
2801 SelectBlock( coords, coords );
2802 }
2803 else
2804 {
2805 SelectBlock( m_currentCellCoords, coords );
2806 }
2807
2808 if (! IsVisible(coords)) {
2809 MakeCellVisible(coords);
2810 // TODO: need to introduce a delay or something here. The
2811 // scrolling is way to fast, at least on MSW.
2812 }
2813 }
2814 }
2815 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2816 {
2817 int cw, ch, left, dummy;
2818 m_gridWin->GetClientSize( &cw, &ch );
2819 CalcUnscrolledPosition( 0, 0, &left, &dummy );
2820
2821 wxClientDC dc( m_gridWin );
2822 PrepareDC( dc );
2823 y = wxMax( y,
2824 m_rowBottoms[m_dragRowOrCol] -
2825 m_rowHeights[m_dragRowOrCol] +
2826 WXGRID_MIN_ROW_HEIGHT );
2827 dc.SetLogicalFunction(wxINVERT);
2828 if ( m_dragLastPos >= 0 )
2829 {
2830 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
2831 }
2832 dc.DrawLine( left, y, left+cw, y );
2833 m_dragLastPos = y;
2834 }
2835 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2836 {
2837 int cw, ch, dummy, top;
2838 m_gridWin->GetClientSize( &cw, &ch );
2839 CalcUnscrolledPosition( 0, 0, &dummy, &top );
2840
2841 wxClientDC dc( m_gridWin );
2842 PrepareDC( dc );
2843 x = wxMax( x,
2844 m_colRights[m_dragRowOrCol] -
2845 m_colWidths[m_dragRowOrCol] + WXGRID_MIN_COL_WIDTH );
2846 dc.SetLogicalFunction(wxINVERT);
2847 if ( m_dragLastPos >= 0 )
2848 {
2849 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
2850 }
2851 dc.DrawLine( x, top, x, top+ch );
2852 m_dragLastPos = x;
2853 }
2854
2855 return;
2856 }
2857
2858 m_isDragging = FALSE;
2859 m_startDragPos = wxDefaultPosition;
2860
2861
2862 if ( coords != wxGridNoCellCoords )
2863 {
2864 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
2865 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
2866 // wxGTK
2867 #if 0
2868 if ( event.Entering() || event.Leaving() )
2869 {
2870 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2871 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
2872 }
2873 else
2874 #endif // 0
2875
2876 // ------------ Left button pressed
2877 //
2878 if ( event.LeftDown() )
2879 {
2880 EnableCellEditControl( FALSE );
2881 if ( event.ShiftDown() )
2882 {
2883 SelectBlock( m_currentCellCoords, coords );
2884 }
2885 else if ( XToEdgeOfCol(x) < 0 &&
2886 YToEdgeOfRow(y) < 0 )
2887 {
2888 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK,
2889 coords.GetRow(),
2890 coords.GetCol(),
2891 event ) )
2892 {
2893 MakeCellVisible( coords );
2894
2895 // if this is the second click on this cell then start
2896 // the edit control
2897 if (m_waitForSlowClick && coords == m_currentCellCoords) {
2898 EnableCellEditControl(TRUE);
2899 ShowCellEditControl();
2900 }
2901 else {
2902 SetCurrentCell( coords );
2903 m_editTimer->Start( 1500, TRUE );
2904 m_waitForSlowClick = TRUE;
2905 }
2906 }
2907 }
2908 }
2909
2910
2911 // ------------ Left double click
2912 //
2913 else if ( event.LeftDClick() )
2914 {
2915 EnableCellEditControl( FALSE );
2916 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
2917 {
2918 SendEvent( EVT_GRID_CELL_LEFT_DCLICK,
2919 coords.GetRow(),
2920 coords.GetCol(),
2921 event );
2922 }
2923 }
2924
2925
2926 // ------------ Left button released
2927 //
2928 else if ( event.LeftUp() )
2929 {
2930 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2931 {
2932 if ( IsSelection() )
2933 {
2934 if (m_winCapture) {
2935 m_winCapture->ReleaseMouse();
2936 m_winCapture = NULL;
2937 }
2938 SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, event );
2939 }
2940
2941 // Show the edit control, if it has
2942 // been hidden for drag-shrinking.
2943 if ( IsCellEditControlEnabled() )
2944 ShowCellEditControl();
2945 }
2946 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2947 {
2948 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2949 DoEndDragResizeRow();
2950
2951 // Note: we are ending the event *after* doing
2952 // default processing in this case
2953 //
2954 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
2955 }
2956 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2957 {
2958 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2959 DoEndDragResizeCol();
2960
2961 // Note: we are ending the event *after* doing
2962 // default processing in this case
2963 //
2964 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2965 }
2966
2967 m_dragLastPos = -1;
2968 }
2969
2970
2971 // ------------ Right button down
2972 //
2973 else if ( event.RightDown() )
2974 {
2975 EnableCellEditControl( FALSE );
2976 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK,
2977 coords.GetRow(),
2978 coords.GetCol(),
2979 event ) )
2980 {
2981 // no default action at the moment
2982 }
2983 }
2984
2985
2986 // ------------ Right double click
2987 //
2988 else if ( event.RightDClick() )
2989 {
2990 EnableCellEditControl( FALSE );
2991 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK,
2992 coords.GetRow(),
2993 coords.GetCol(),
2994 event ) )
2995 {
2996 // no default action at the moment
2997 }
2998 }
2999
3000 // ------------ Moving and no button action
3001 //
3002 else if ( event.Moving() && !event.IsButton() )
3003 {
3004 int dragRow = YToEdgeOfRow( y );
3005 int dragCol = XToEdgeOfCol( x );
3006
3007 // Dragging on the corner of a cell to resize in both
3008 // directions is not implemented yet...
3009 //
3010 if ( dragRow >= 0 && dragCol >= 0 )
3011 {
3012 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
3013 return;
3014 }
3015
3016 if ( dragRow >= 0 )
3017 {
3018 m_dragRowOrCol = dragRow;
3019
3020 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
3021 {
3022 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
3023 }
3024
3025 return;
3026 }
3027
3028 if ( dragCol >= 0 )
3029 {
3030 m_dragRowOrCol = dragCol;
3031
3032 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
3033 {
3034 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
3035 }
3036
3037 return;
3038 }
3039
3040 // Neither on a row or col edge
3041 //
3042 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
3043 {
3044 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
3045 }
3046 }
3047 }
3048 }
3049
3050
3051 void wxGrid::DoEndDragResizeRow()
3052 {
3053 if ( m_dragLastPos >= 0 )
3054 {
3055 // erase the last line and resize the row
3056 //
3057 int cw, ch, left, dummy;
3058 m_gridWin->GetClientSize( &cw, &ch );
3059 CalcUnscrolledPosition( 0, 0, &left, &dummy );
3060
3061 wxClientDC dc( m_gridWin );
3062 PrepareDC( dc );
3063 dc.SetLogicalFunction( wxINVERT );
3064 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
3065 HideCellEditControl();
3066
3067 int rowTop = m_rowBottoms[m_dragRowOrCol] - m_rowHeights[m_dragRowOrCol];
3068 SetRowSize( m_dragRowOrCol,
3069 wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
3070
3071 if ( !GetBatchCount() )
3072 {
3073 // Only needed to get the correct rect.y:
3074 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
3075 rect.x = 0;
3076 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
3077 rect.width = m_rowLabelWidth;
3078 rect.height = ch - rect.y;
3079 m_rowLabelWin->Refresh( TRUE, &rect );
3080 rect.width = cw;
3081 m_gridWin->Refresh( FALSE, &rect );
3082 }
3083
3084 ShowCellEditControl();
3085 }
3086 }
3087
3088
3089 void wxGrid::DoEndDragResizeCol()
3090 {
3091 if ( m_dragLastPos >= 0 )
3092 {
3093 // erase the last line and resize the col
3094 //
3095 int cw, ch, dummy, top;
3096 m_gridWin->GetClientSize( &cw, &ch );
3097 CalcUnscrolledPosition( 0, 0, &dummy, &top );
3098
3099 wxClientDC dc( m_gridWin );
3100 PrepareDC( dc );
3101 dc.SetLogicalFunction( wxINVERT );
3102 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
3103 HideCellEditControl();
3104
3105 int colLeft = m_colRights[m_dragRowOrCol] - m_colWidths[m_dragRowOrCol];
3106 SetColSize( m_dragRowOrCol,
3107 wxMax( m_dragLastPos - colLeft, WXGRID_MIN_COL_WIDTH ) );
3108
3109 if ( !GetBatchCount() )
3110 {
3111 // Only needed to get the correct rect.x:
3112 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
3113 rect.y = 0;
3114 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
3115 rect.width = cw - rect.x;
3116 rect.height = m_colLabelHeight;
3117 m_colLabelWin->Refresh( TRUE, &rect );
3118 rect.height = ch;
3119 m_gridWin->Refresh( FALSE, &rect );
3120 }
3121
3122 ShowCellEditControl();
3123 }
3124 }
3125
3126
3127
3128 //
3129 // ------ interaction with data model
3130 //
3131 bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
3132 {
3133 switch ( msg.GetId() )
3134 {
3135 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
3136 return GetModelValues();
3137
3138 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
3139 return SetModelValues();
3140
3141 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
3142 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
3143 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
3144 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
3145 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
3146 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
3147 return Redimension( msg );
3148
3149 default:
3150 return FALSE;
3151 }
3152 }
3153
3154
3155
3156 // The behaviour of this function depends on the grid table class
3157 // Clear() function. For the default wxGridStringTable class the
3158 // behavious is to replace all cell contents with wxEmptyString but
3159 // not to change the number of rows or cols.
3160 //
3161 void wxGrid::ClearGrid()
3162 {
3163 if ( m_table )
3164 {
3165 m_table->Clear();
3166 SetEditControlValue();
3167 if ( !GetBatchCount() ) m_gridWin->Refresh();
3168 }
3169 }
3170
3171
3172 bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
3173 {
3174 // TODO: something with updateLabels flag
3175
3176 if ( !m_created )
3177 {
3178 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
3179 return FALSE;
3180 }
3181
3182 if ( m_table )
3183 {
3184 bool ok = m_table->InsertRows( pos, numRows );
3185
3186 // the table will have sent the results of the insert row
3187 // operation to this view object as a grid table message
3188 //
3189 if ( ok )
3190 {
3191 if ( m_numCols == 0 )
3192 {
3193 m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
3194 //
3195 // TODO: perhaps instead of appending the default number of cols
3196 // we should remember what the last non-zero number of cols was ?
3197 //
3198 }
3199
3200 if ( m_currentCellCoords == wxGridNoCellCoords )
3201 {
3202 // if we have just inserted cols into an empty grid the current
3203 // cell will be undefined...
3204 //
3205 SetCurrentCell( 0, 0 );
3206 }
3207
3208 ClearSelection();
3209 if ( !GetBatchCount() ) Refresh();
3210 }
3211
3212 SetEditControlValue();
3213 return ok;
3214 }
3215 else
3216 {
3217 return FALSE;
3218 }
3219 }
3220
3221
3222 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
3223 {
3224 // TODO: something with updateLabels flag
3225
3226 if ( !m_created )
3227 {
3228 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
3229 return FALSE;
3230 }
3231
3232 if ( m_table && m_table->AppendRows( numRows ) )
3233 {
3234 if ( m_currentCellCoords == wxGridNoCellCoords )
3235 {
3236 // if we have just inserted cols into an empty grid the current
3237 // cell will be undefined...
3238 //
3239 SetCurrentCell( 0, 0 );
3240 }
3241
3242 // the table will have sent the results of the append row
3243 // operation to this view object as a grid table message
3244 //
3245 ClearSelection();
3246 if ( !GetBatchCount() ) Refresh();
3247 return TRUE;
3248 }
3249 else
3250 {
3251 return FALSE;
3252 }
3253 }
3254
3255
3256 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
3257 {
3258 // TODO: something with updateLabels flag
3259
3260 if ( !m_created )
3261 {
3262 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
3263 return FALSE;
3264 }
3265
3266 if ( m_table && m_table->DeleteRows( pos, numRows ) )
3267 {
3268 // the table will have sent the results of the delete row
3269 // operation to this view object as a grid table message
3270 //
3271 if ( m_numRows > 0 )
3272 SetEditControlValue();
3273 else
3274 HideCellEditControl();
3275
3276 ClearSelection();
3277 if ( !GetBatchCount() ) Refresh();
3278 return TRUE;
3279 }
3280 else
3281 {
3282 return FALSE;
3283 }
3284 }
3285
3286
3287 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
3288 {
3289 // TODO: something with updateLabels flag
3290
3291 if ( !m_created )
3292 {
3293 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
3294 return FALSE;
3295 }
3296
3297 if ( m_table )
3298 {
3299 HideCellEditControl();
3300 bool ok = m_table->InsertCols( pos, numCols );
3301
3302 // the table will have sent the results of the insert col
3303 // operation to this view object as a grid table message
3304 //
3305 if ( ok )
3306 {
3307 if ( m_currentCellCoords == wxGridNoCellCoords )
3308 {
3309 // if we have just inserted cols into an empty grid the current
3310 // cell will be undefined...
3311 //
3312 SetCurrentCell( 0, 0 );
3313 }
3314
3315 ClearSelection();
3316 if ( !GetBatchCount() ) Refresh();
3317 }
3318
3319 SetEditControlValue();
3320 return ok;
3321 }
3322 else
3323 {
3324 return FALSE;
3325 }
3326 }
3327
3328
3329 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
3330 {
3331 // TODO: something with updateLabels flag
3332
3333 if ( !m_created )
3334 {
3335 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
3336 return FALSE;
3337 }
3338
3339 if ( m_table && m_table->AppendCols( numCols ) )
3340 {
3341 // the table will have sent the results of the append col
3342 // operation to this view object as a grid table message
3343 //
3344 if ( m_currentCellCoords == wxGridNoCellCoords )
3345 {
3346 // if we have just inserted cols into an empty grid the current
3347 // cell will be undefined...
3348 //
3349 SetCurrentCell( 0, 0 );
3350 }
3351
3352 ClearSelection();
3353 if ( !GetBatchCount() ) Refresh();
3354 return TRUE;
3355 }
3356 else
3357 {
3358 return FALSE;
3359 }
3360 }
3361
3362
3363 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
3364 {
3365 // TODO: something with updateLabels flag
3366
3367 if ( !m_created )
3368 {
3369 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
3370 return FALSE;
3371 }
3372
3373 if ( m_table && m_table->DeleteCols( pos, numCols ) )
3374 {
3375 // the table will have sent the results of the delete col
3376 // operation to this view object as a grid table message
3377 //
3378 if ( m_numCols > 0 )
3379 SetEditControlValue();
3380 else
3381 HideCellEditControl();
3382
3383 ClearSelection();
3384 if ( !GetBatchCount() ) Refresh();
3385 return TRUE;
3386 }
3387 else
3388 {
3389 return FALSE;
3390 }
3391 }
3392
3393
3394
3395 //
3396 // ----- event handlers
3397 //
3398
3399 // Generate a grid event based on a mouse event and
3400 // return the result of ProcessEvent()
3401 //
3402 bool wxGrid::SendEvent( const wxEventType type,
3403 int row, int col,
3404 wxMouseEvent& mouseEv )
3405 {
3406 if ( type == EVT_GRID_ROW_SIZE ||
3407 type == EVT_GRID_COL_SIZE )
3408 {
3409 int rowOrCol = (row == -1 ? col : row);
3410
3411 wxGridSizeEvent gridEvt( GetId(),
3412 type,
3413 this,
3414 rowOrCol,
3415 mouseEv.GetX(), mouseEv.GetY(),
3416 mouseEv.ControlDown(),
3417 mouseEv.ShiftDown(),
3418 mouseEv.AltDown(),
3419 mouseEv.MetaDown() );
3420
3421 return GetEventHandler()->ProcessEvent(gridEvt);
3422 }
3423 else if ( type == EVT_GRID_RANGE_SELECT )
3424 {
3425 wxGridRangeSelectEvent gridEvt( GetId(),
3426 type,
3427 this,
3428 m_selectedTopLeft,
3429 m_selectedBottomRight,
3430 mouseEv.ControlDown(),
3431 mouseEv.ShiftDown(),
3432 mouseEv.AltDown(),
3433 mouseEv.MetaDown() );
3434
3435 return GetEventHandler()->ProcessEvent(gridEvt);
3436 }
3437 else
3438 {
3439 wxGridEvent gridEvt( GetId(),
3440 type,
3441 this,
3442 row, col,
3443 mouseEv.GetX(), mouseEv.GetY(),
3444 mouseEv.ControlDown(),
3445 mouseEv.ShiftDown(),
3446 mouseEv.AltDown(),
3447 mouseEv.MetaDown() );
3448
3449 return GetEventHandler()->ProcessEvent(gridEvt);
3450 }
3451 }
3452
3453
3454 // Generate a grid event of specified type and return the result
3455 // of ProcessEvent().
3456 //
3457 bool wxGrid::SendEvent( const wxEventType type,
3458 int row, int col )
3459 {
3460 if ( type == EVT_GRID_ROW_SIZE ||
3461 type == EVT_GRID_COL_SIZE )
3462 {
3463 int rowOrCol = (row == -1 ? col : row);
3464
3465 wxGridSizeEvent gridEvt( GetId(),
3466 type,
3467 this,
3468 rowOrCol );
3469
3470 return GetEventHandler()->ProcessEvent(gridEvt);
3471 }
3472 else
3473 {
3474 wxGridEvent gridEvt( GetId(),
3475 type,
3476 this,
3477 row, col );
3478
3479 return GetEventHandler()->ProcessEvent(gridEvt);
3480 }
3481 }
3482
3483
3484 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
3485 {
3486 wxPaintDC dc( this );
3487
3488 if ( m_currentCellCoords == wxGridNoCellCoords &&
3489 m_numRows && m_numCols )
3490 {
3491 m_currentCellCoords.Set(0, 0);
3492 SetEditControlValue();
3493 ShowCellEditControl();
3494 }
3495
3496 m_displayed = TRUE;
3497 }
3498
3499
3500 // This is just here to make sure that CalcDimensions gets called when
3501 // the grid view is resized... then the size event is skipped to allow
3502 // the box sizers to handle everything
3503 //
3504 void wxGrid::OnSize( wxSizeEvent& event )
3505 {
3506 CalcWindowSizes();
3507 CalcDimensions();
3508 }
3509
3510
3511 void wxGrid::OnKeyDown( wxKeyEvent& event )
3512 {
3513 if ( m_inOnKeyDown )
3514 {
3515 // shouldn't be here - we are going round in circles...
3516 //
3517 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
3518 }
3519
3520 m_inOnKeyDown = TRUE;
3521
3522 // propagate the event up and see if it gets processed
3523 //
3524 wxWindow *parent = GetParent();
3525 wxKeyEvent keyEvt( event );
3526 keyEvt.SetEventObject( parent );
3527
3528 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
3529 {
3530 // try local handlers
3531 //
3532 switch ( event.KeyCode() )
3533 {
3534 case WXK_UP:
3535 if ( event.ControlDown() )
3536 {
3537 MoveCursorUpBlock();
3538 }
3539 else
3540 {
3541 MoveCursorUp();
3542 }
3543 break;
3544
3545 case WXK_DOWN:
3546 if ( event.ControlDown() )
3547 {
3548 MoveCursorDownBlock();
3549 }
3550 else
3551 {
3552 MoveCursorDown();
3553 }
3554 break;
3555
3556 case WXK_LEFT:
3557 if ( event.ControlDown() )
3558 {
3559 MoveCursorLeftBlock();
3560 }
3561 else
3562 {
3563 MoveCursorLeft();
3564 }
3565 break;
3566
3567 case WXK_RIGHT:
3568 if ( event.ControlDown() )
3569 {
3570 MoveCursorRightBlock();
3571 }
3572 else
3573 {
3574 MoveCursorRight();
3575 }
3576 break;
3577
3578 case WXK_RETURN:
3579 if ( event.ControlDown() )
3580 {
3581 event.Skip(); // to let the edit control have the return
3582 }
3583 else
3584 {
3585 MoveCursorDown();
3586 }
3587 break;
3588
3589 case WXK_TAB:
3590 if (event.ShiftDown())
3591 MoveCursorLeft();
3592 else
3593 MoveCursorRight();
3594 break;
3595
3596 case WXK_HOME:
3597 if ( event.ControlDown() )
3598 {
3599 MakeCellVisible( 0, 0 );
3600 SetCurrentCell( 0, 0 );
3601 }
3602 else
3603 {
3604 event.Skip();
3605 }
3606 break;
3607
3608 case WXK_END:
3609 if ( event.ControlDown() )
3610 {
3611 MakeCellVisible( m_numRows-1, m_numCols-1 );
3612 SetCurrentCell( m_numRows-1, m_numCols-1 );
3613 }
3614 else
3615 {
3616 event.Skip();
3617 }
3618 break;
3619
3620 case WXK_PRIOR:
3621 MovePageUp();
3622 break;
3623
3624 case WXK_NEXT:
3625 MovePageDown();
3626 break;
3627
3628 // We don't want these keys to trigger the edit control, any others?
3629 case WXK_SHIFT:
3630 case WXK_ALT:
3631 case WXK_CONTROL:
3632 case WXK_CAPITAL:
3633 event.Skip();
3634 break;
3635
3636 case WXK_SPACE:
3637 if ( !IsEditable() )
3638 {
3639 MoveCursorRight();
3640 break;
3641 }
3642 // Otherwise fall through to default
3643
3644 default:
3645 // now try the cell edit control
3646 //
3647 if ( !IsCellEditControlEnabled() )
3648 EnableCellEditControl( TRUE );
3649 if (IsCellEditControlEnabled()) {
3650 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
3651 attr->GetEditor()->StartingKey(event);
3652 attr->DecRef();
3653 }
3654 break;
3655 }
3656 }
3657
3658 m_inOnKeyDown = FALSE;
3659 }
3660
3661
3662 void wxGrid::OnEraseBackground(wxEraseEvent&)
3663 { }
3664
3665
3666 void wxGrid::OnEditTimer(wxTimerEvent&)
3667 {
3668 m_waitForSlowClick = FALSE;
3669 }
3670
3671
3672
3673 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
3674 {
3675 if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
3676 {
3677 // the event has been intercepted - do nothing
3678 return;
3679 }
3680
3681 if ( m_displayed &&
3682 m_currentCellCoords != wxGridNoCellCoords )
3683 {
3684 HideCellEditControl();
3685 SaveEditControlValue();
3686 EnableCellEditControl(FALSE);
3687
3688 // Clear the old current cell highlight
3689 wxRect r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords);
3690 r.x--; r.y--; r.width++; r.height++;
3691 m_gridWin->Refresh( FALSE, &r );
3692 }
3693
3694 m_currentCellCoords = coords;
3695
3696 SetEditControlValue();
3697
3698 if ( m_displayed )
3699 {
3700 #if 0
3701 ShowCellEditControl();
3702 #else
3703 wxClientDC dc(m_gridWin);
3704 PrepareDC(dc);
3705 DrawCellHighlight(dc);
3706 #endif
3707
3708 if ( IsSelection() )
3709 {
3710 wxRect r( SelectionToDeviceRect() );
3711 ClearSelection();
3712 if ( !GetBatchCount() ) m_gridWin->Refresh( FALSE, &r );
3713 }
3714 }
3715 }
3716
3717
3718 //
3719 // ------ functions to get/send data (see also public functions)
3720 //
3721
3722 bool wxGrid::GetModelValues()
3723 {
3724 if ( m_table )
3725 {
3726 // all we need to do is repaint the grid
3727 //
3728 m_gridWin->Refresh();
3729 return TRUE;
3730 }
3731
3732 return FALSE;
3733 }
3734
3735
3736 bool wxGrid::SetModelValues()
3737 {
3738 int row, col;
3739
3740 if ( m_table )
3741 {
3742 for ( row = 0; row < m_numRows; row++ )
3743 {
3744 for ( col = 0; col < m_numCols; col++ )
3745 {
3746 m_table->SetValue( row, col, GetCellValue(row, col) );
3747 }
3748 }
3749
3750 return TRUE;
3751 }
3752
3753 return FALSE;
3754 }
3755
3756
3757
3758 // Note - this function only draws cells that are in the list of
3759 // exposed cells (usually set from the update region by
3760 // CalcExposedCells)
3761 //
3762 void wxGrid::DrawGridCellArea( wxDC& dc )
3763 {
3764 if ( !m_numRows || !m_numCols ) return;
3765
3766 size_t i;
3767 size_t numCells = m_cellsExposed.GetCount();
3768
3769 for ( i = 0; i < numCells; i++ )
3770 {
3771 DrawCell( dc, m_cellsExposed[i] );
3772 }
3773 }
3774
3775
3776 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
3777 {
3778 int row = coords.GetRow();
3779 int col = coords.GetCol();
3780
3781 if ( m_colWidths[col] <= 0 || m_rowHeights[row] <= 0 )
3782 return;
3783
3784 // we draw the cell border ourselves
3785 #if !WXGRID_DRAW_LINES
3786 if ( m_gridLinesEnabled )
3787 DrawCellBorder( dc, coords );
3788 #endif
3789
3790 // but all the rest is drawn by the cell renderer and hence may be
3791 // customized
3792 wxRect rect;
3793 rect.x = m_colRights[col] - m_colWidths[col];
3794 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3795 rect.width = m_colWidths[col];
3796 rect.height = m_rowHeights[row];
3797
3798 wxGridCellAttr* attr = GetCellAttr(row, col);
3799 attr->GetRenderer()->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
3800 attr->DecRef();
3801
3802 if (m_currentCellCoords == coords)
3803 DrawCellHighlight(dc);
3804 }
3805
3806
3807 void wxGrid::DrawCellHighlight( wxDC& dc )
3808 {
3809 int row = m_currentCellCoords.GetRow();
3810 int col = m_currentCellCoords.GetCol();
3811
3812 if ( m_colWidths[col] <= 0 || m_rowHeights[row] <= 0 )
3813 return;
3814
3815 wxRect rect;
3816 rect.x = m_colRights[col] - m_colWidths[col];
3817 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3818 rect.width = m_colWidths[col] - 1;
3819 rect.height = m_rowHeights[row] - 1;
3820
3821 dc.SetPen(wxPen(m_gridLineColour, 3, wxSOLID));
3822 dc.SetBrush(*wxTRANSPARENT_BRUSH);
3823 //dc.SetLogicalFunction(wxINVERT);
3824
3825 dc.DrawRectangle(rect);
3826 }
3827
3828 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
3829 {
3830 if ( m_colWidths[coords.GetCol()] <=0 ||
3831 m_rowHeights[coords.GetRow()] <= 0 ) return;
3832
3833 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3834 int row = coords.GetRow();
3835 int col = coords.GetCol();
3836
3837 // right hand border
3838 //
3839 dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
3840 m_colRights[col], m_rowBottoms[row] );
3841
3842 // bottom border
3843 //
3844 dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
3845 m_colRights[col], m_rowBottoms[row] );
3846 }
3847
3848
3849 // TODO: remove this ???
3850 // This is used to redraw all grid lines e.g. when the grid line colour
3851 // has been changed
3852 //
3853 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg )
3854 {
3855 if ( !m_gridLinesEnabled ||
3856 !m_numRows ||
3857 !m_numCols ) return;
3858
3859 int top, bottom, left, right;
3860
3861 if (reg.IsEmpty()){
3862 int cw, ch;
3863 m_gridWin->GetClientSize(&cw, &ch);
3864
3865 // virtual coords of visible area
3866 //
3867 CalcUnscrolledPosition( 0, 0, &left, &top );
3868 CalcUnscrolledPosition( cw, ch, &right, &bottom );
3869 }
3870 else{
3871 wxCoord x, y, w, h;
3872 reg.GetBox(x, y, w, h);
3873 CalcUnscrolledPosition( x, y, &left, &top );
3874 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
3875 }
3876
3877 // avoid drawing grid lines past the last row and col
3878 //
3879 right = wxMin( right, m_colRights[m_numCols-1] );
3880 bottom = wxMin( bottom, m_rowBottoms[m_numRows-1] );
3881
3882 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3883
3884 // horizontal grid lines
3885 //
3886 int i;
3887 for ( i = 0; i < m_numRows; i++ )
3888 {
3889 if ( m_rowBottoms[i]-1 > bottom )
3890 {
3891 break;
3892 }
3893 else if ( m_rowBottoms[i]-1 >= top )
3894 {
3895 dc.DrawLine( left, m_rowBottoms[i]-1, right, m_rowBottoms[i]-1 );
3896 }
3897 }
3898
3899
3900 // vertical grid lines
3901 //
3902 for ( i = 0; i < m_numCols; i++ )
3903 {
3904 if ( m_colRights[i]-1 > right )
3905 {
3906 break;
3907 }
3908 else if ( m_colRights[i]-1 >= left )
3909 {
3910 dc.DrawLine( m_colRights[i]-1, top, m_colRights[i]-1, bottom );
3911 }
3912 }
3913 }
3914
3915
3916 void wxGrid::DrawRowLabels( wxDC& dc )
3917 {
3918 if ( !m_numRows || !m_numCols ) return;
3919
3920 size_t i;
3921 size_t numLabels = m_rowLabelsExposed.GetCount();
3922
3923 for ( i = 0; i < numLabels; i++ )
3924 {
3925 DrawRowLabel( dc, m_rowLabelsExposed[i] );
3926 }
3927 }
3928
3929
3930 void wxGrid::DrawRowLabel( wxDC& dc, int row )
3931 {
3932 if ( m_rowHeights[row] <= 0 ) return;
3933
3934 int rowTop = m_rowBottoms[row] - m_rowHeights[row];
3935
3936 dc.SetPen( *wxBLACK_PEN );
3937 dc.DrawLine( m_rowLabelWidth-1, rowTop,
3938 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3939
3940 dc.DrawLine( 0, m_rowBottoms[row]-1,
3941 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3942
3943 dc.SetPen( *wxWHITE_PEN );
3944 dc.DrawLine( 0, rowTop, 0, m_rowBottoms[row]-1 );
3945 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
3946
3947 dc.SetBackgroundMode( wxTRANSPARENT );
3948 dc.SetTextForeground( GetLabelTextColour() );
3949 dc.SetFont( GetLabelFont() );
3950
3951 int hAlign, vAlign;
3952 GetRowLabelAlignment( &hAlign, &vAlign );
3953
3954 wxRect rect;
3955 rect.SetX( 2 );
3956 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
3957 rect.SetWidth( m_rowLabelWidth - 4 );
3958 rect.SetHeight( m_rowHeights[row] - 4 );
3959 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
3960 }
3961
3962
3963 void wxGrid::DrawColLabels( wxDC& dc )
3964 {
3965 if ( !m_numRows || !m_numCols ) return;
3966
3967 size_t i;
3968 size_t numLabels = m_colLabelsExposed.GetCount();
3969
3970 for ( i = 0; i < numLabels; i++ )
3971 {
3972 DrawColLabel( dc, m_colLabelsExposed[i] );
3973 }
3974 }
3975
3976
3977 void wxGrid::DrawColLabel( wxDC& dc, int col )
3978 {
3979 if ( m_colWidths[col] <= 0 ) return;
3980
3981 int colLeft = m_colRights[col] - m_colWidths[col];
3982
3983 dc.SetPen( *wxBLACK_PEN );
3984 dc.DrawLine( m_colRights[col]-1, 0,
3985 m_colRights[col]-1, m_colLabelHeight-1 );
3986
3987 dc.DrawLine( colLeft, m_colLabelHeight-1,
3988 m_colRights[col]-1, m_colLabelHeight-1 );
3989
3990 dc.SetPen( *wxWHITE_PEN );
3991 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
3992 dc.DrawLine( colLeft, 0, m_colRights[col]-1, 0 );
3993
3994 dc.SetBackgroundMode( wxTRANSPARENT );
3995 dc.SetTextForeground( GetLabelTextColour() );
3996 dc.SetFont( GetLabelFont() );
3997
3998 dc.SetBackgroundMode( wxTRANSPARENT );
3999 dc.SetTextForeground( GetLabelTextColour() );
4000 dc.SetFont( GetLabelFont() );
4001
4002 int hAlign, vAlign;
4003 GetColLabelAlignment( &hAlign, &vAlign );
4004
4005 wxRect rect;
4006 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
4007 rect.SetY( 2 );
4008 rect.SetWidth( m_colWidths[col] - 4 );
4009 rect.SetHeight( m_colLabelHeight - 4 );
4010 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
4011 }
4012
4013
4014 void wxGrid::DrawTextRectangle( wxDC& dc,
4015 const wxString& value,
4016 const wxRect& rect,
4017 int horizAlign,
4018 int vertAlign )
4019 {
4020 long textWidth, textHeight;
4021 long lineWidth, lineHeight;
4022 wxArrayString lines;
4023
4024 dc.SetClippingRegion( rect );
4025 StringToLines( value, lines );
4026 if ( lines.GetCount() )
4027 {
4028 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
4029 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
4030
4031 float x, y;
4032 switch ( horizAlign )
4033 {
4034 case wxRIGHT:
4035 x = rect.x + (rect.width - textWidth - 1);
4036 break;
4037
4038 case wxCENTRE:
4039 x = rect.x + ((rect.width - textWidth)/2);
4040 break;
4041
4042 case wxLEFT:
4043 default:
4044 x = rect.x + 1;
4045 break;
4046 }
4047
4048 switch ( vertAlign )
4049 {
4050 case wxBOTTOM:
4051 y = rect.y + (rect.height - textHeight - 1);
4052 break;
4053
4054 case wxCENTRE:
4055 y = rect.y + ((rect.height - textHeight)/2);
4056 break;
4057
4058 case wxTOP:
4059 default:
4060 y = rect.y + 1;
4061 break;
4062 }
4063
4064 for ( size_t i = 0; i < lines.GetCount(); i++ )
4065 {
4066 dc.DrawText( lines[i], (long)x, (long)y );
4067 y += lineHeight;
4068 }
4069 }
4070
4071 dc.DestroyClippingRegion();
4072 }
4073
4074
4075 // Split multi line text up into an array of strings. Any existing
4076 // contents of the string array are preserved.
4077 //
4078 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
4079 {
4080 int startPos = 0;
4081 int pos;
4082 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
4083 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
4084
4085 while ( startPos < (int)tVal.Length() )
4086 {
4087 pos = tVal.Mid(startPos).Find( eol );
4088 if ( pos < 0 )
4089 {
4090 break;
4091 }
4092 else if ( pos == 0 )
4093 {
4094 lines.Add( wxEmptyString );
4095 }
4096 else
4097 {
4098 lines.Add( value.Mid(startPos, pos) );
4099 }
4100 startPos += pos+1;
4101 }
4102 if ( startPos < (int)value.Length() )
4103 {
4104 lines.Add( value.Mid( startPos ) );
4105 }
4106 }
4107
4108
4109 void wxGrid::GetTextBoxSize( wxDC& dc,
4110 wxArrayString& lines,
4111 long *width, long *height )
4112 {
4113 long w = 0;
4114 long h = 0;
4115 long lineW, lineH;
4116
4117 size_t i;
4118 for ( i = 0; i < lines.GetCount(); i++ )
4119 {
4120 dc.GetTextExtent( lines[i], &lineW, &lineH );
4121 w = wxMax( w, lineW );
4122 h += lineH;
4123 }
4124
4125 *width = w;
4126 *height = h;
4127 }
4128
4129
4130 //
4131 // ------ Edit control functions
4132 //
4133
4134
4135 void wxGrid::EnableEditing( bool edit )
4136 {
4137 // TODO: improve this ?
4138 //
4139 if ( edit != m_editable )
4140 {
4141 m_editable = edit;
4142
4143 EnableCellEditControl(m_editable);
4144 }
4145 }
4146
4147
4148 void wxGrid::EnableCellEditControl( bool enable )
4149 {
4150 if (! m_editable)
4151 return;
4152
4153 if ( m_currentCellCoords == wxGridNoCellCoords )
4154 SetCurrentCell( 0, 0 );
4155
4156 if ( enable != m_cellEditCtrlEnabled )
4157 {
4158 if ( enable )
4159 {
4160 m_cellEditCtrlEnabled = enable;
4161 SetEditControlValue();
4162 ShowCellEditControl();
4163 }
4164 else
4165 {
4166 HideCellEditControl();
4167 SaveEditControlValue();
4168 m_cellEditCtrlEnabled = enable;
4169 }
4170 }
4171 }
4172
4173
4174 void wxGrid::ShowCellEditControl()
4175 {
4176 if ( IsCellEditControlEnabled() )
4177 {
4178 if ( !IsVisible( m_currentCellCoords ) )
4179 {
4180 return;
4181 }
4182 else
4183 {
4184 wxRect rect = CellToRect( m_currentCellCoords );
4185 int row = m_currentCellCoords.GetRow();
4186 int col = m_currentCellCoords.GetCol();
4187
4188 // convert to scrolled coords
4189 //
4190 int left, top, right, bottom;
4191 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
4192 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
4193 left--; top--; right--; bottom--; // cell is shifted by one pixel
4194 int cw, ch;
4195 m_gridWin->GetClientSize( &cw, &ch );
4196
4197 // Make the edit control large enough to allow for internal margins
4198 // TODO: remove this if the text ctrl sizing is improved esp. for unix
4199 //
4200 int extra;
4201 #if defined(__WXMOTIF__)
4202 if ( row == 0 || col == 0 )
4203 {
4204 extra = 2;
4205 }
4206 else
4207 {
4208 extra = 4;
4209 }
4210 #else
4211 if ( row == 0 || col == 0 )
4212 {
4213 extra = 1;
4214 }
4215 else
4216 {
4217 extra = 2;
4218 }
4219 #endif
4220
4221 #if defined(__WXGTK__)
4222 int top_diff = 0;
4223 int left_diff = 0;
4224 if (left != 0) left_diff++;
4225 if (top != 0) top_diff++;
4226 rect.SetLeft( left + left_diff );
4227 rect.SetTop( top + top_diff );
4228 rect.SetRight( rect.GetRight() - left_diff );
4229 rect.SetBottom( rect.GetBottom() - top_diff );
4230 #else
4231 rect.SetLeft( wxMax(0, left - extra) );
4232 rect.SetTop( wxMax(0, top - extra) );
4233 rect.SetRight( rect.GetRight() + 2*extra );
4234 rect.SetBottom( rect.GetBottom() + 2*extra );
4235 #endif
4236
4237 wxGridCellAttr* attr = GetCellAttr(row, col);
4238 wxGridCellEditor* editor = attr->GetEditor();
4239 if (! editor->IsCreated()) {
4240 editor->Create(m_gridWin, -1,
4241 new wxGridCellEditorEvtHandler(this, editor));
4242 }
4243
4244 editor->SetSize( rect );
4245 editor->Show( TRUE );
4246 editor->BeginEdit(row, col, this, attr);
4247 attr->DecRef();
4248 }
4249 }
4250 }
4251
4252
4253 void wxGrid::HideCellEditControl()
4254 {
4255 if ( IsCellEditControlEnabled() )
4256 {
4257 int row = m_currentCellCoords.GetRow();
4258 int col = m_currentCellCoords.GetCol();
4259
4260 wxGridCellAttr* attr = GetCellAttr(row, col);
4261 attr->GetEditor()->Show( FALSE );
4262 attr->DecRef();
4263 m_gridWin->SetFocus();
4264 }
4265 }
4266
4267
4268 void wxGrid::SetEditControlValue( const wxString& value )
4269 {
4270 }
4271
4272
4273 void wxGrid::SaveEditControlValue()
4274 {
4275 if (IsCellEditControlEnabled()) {
4276 int row = m_currentCellCoords.GetRow();
4277 int col = m_currentCellCoords.GetCol();
4278
4279 wxGridCellAttr* attr = GetCellAttr(row, col);
4280 bool changed = attr->GetEditor()->EndEdit(row, col, TRUE, this, attr);
4281
4282 attr->DecRef();
4283
4284 if (changed) {
4285 SendEvent( EVT_GRID_CELL_CHANGE,
4286 m_currentCellCoords.GetRow(),
4287 m_currentCellCoords.GetCol() );
4288 }
4289 }
4290 }
4291
4292
4293 //
4294 // ------ Grid location functions
4295 // Note that all of these functions work with the logical coordinates of
4296 // grid cells and labels so you will need to convert from device
4297 // coordinates for mouse events etc.
4298 //
4299
4300 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
4301 {
4302 int row = YToRow(y);
4303 int col = XToCol(x);
4304
4305 if ( row == -1 || col == -1 )
4306 {
4307 coords = wxGridNoCellCoords;
4308 }
4309 else
4310 {
4311 coords.Set( row, col );
4312 }
4313 }
4314
4315
4316 int wxGrid::YToRow( int y )
4317 {
4318 int i;
4319
4320 for ( i = 0; i < m_numRows; i++ )
4321 {
4322 if ( y < m_rowBottoms[i] ) return i;
4323 }
4324
4325 return m_numRows; //-1;
4326 }
4327
4328
4329 int wxGrid::XToCol( int x )
4330 {
4331 int i;
4332
4333 for ( i = 0; i < m_numCols; i++ )
4334 {
4335 if ( x < m_colRights[i] ) return i;
4336 }
4337
4338 return m_numCols; //-1;
4339 }
4340
4341
4342 // return the row number that that the y coord is near the edge of, or
4343 // -1 if not near an edge
4344 //
4345 int wxGrid::YToEdgeOfRow( int y )
4346 {
4347 int i, d;
4348
4349 for ( i = 0; i < m_numRows; i++ )
4350 {
4351 if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
4352 {
4353 d = abs( y - m_rowBottoms[i] );
4354 {
4355 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
4356 }
4357 }
4358 }
4359
4360 return -1;
4361 }
4362
4363
4364 // return the col number that that the x coord is near the edge of, or
4365 // -1 if not near an edge
4366 //
4367 int wxGrid::XToEdgeOfCol( int x )
4368 {
4369 int i, d;
4370
4371 for ( i = 0; i < m_numCols; i++ )
4372 {
4373 if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
4374 {
4375 d = abs( x - m_colRights[i] );
4376 {
4377 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
4378 }
4379 }
4380 }
4381
4382 return -1;
4383 }
4384
4385
4386 wxRect wxGrid::CellToRect( int row, int col )
4387 {
4388 wxRect rect( -1, -1, -1, -1 );
4389
4390 if ( row >= 0 && row < m_numRows &&
4391 col >= 0 && col < m_numCols )
4392 {
4393 rect.x = m_colRights[col] - m_colWidths[col];
4394 rect.y = m_rowBottoms[row] - m_rowHeights[row];
4395 rect.width = m_colWidths[col];
4396 rect.height = m_rowHeights[ row ];
4397 }
4398
4399 return rect;
4400 }
4401
4402
4403 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
4404 {
4405 // get the cell rectangle in logical coords
4406 //
4407 wxRect r( CellToRect( row, col ) );
4408
4409 // convert to device coords
4410 //
4411 int left, top, right, bottom;
4412 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4413 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
4414
4415 // check against the client area of the grid window
4416 //
4417 int cw, ch;
4418 m_gridWin->GetClientSize( &cw, &ch );
4419
4420 if ( wholeCellVisible )
4421 {
4422 // is the cell wholly visible ?
4423 //
4424 return ( left >= 0 && right <= cw &&
4425 top >= 0 && bottom <= ch );
4426 }
4427 else
4428 {
4429 // is the cell partly visible ?
4430 //
4431 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
4432 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
4433 }
4434 }
4435
4436
4437 // make the specified cell location visible by doing a minimal amount
4438 // of scrolling
4439 //
4440 void wxGrid::MakeCellVisible( int row, int col )
4441 {
4442 int i;
4443 int xpos = -1, ypos = -1;
4444
4445 if ( row >= 0 && row < m_numRows &&
4446 col >= 0 && col < m_numCols )
4447 {
4448 // get the cell rectangle in logical coords
4449 //
4450 wxRect r( CellToRect( row, col ) );
4451
4452 // convert to device coords
4453 //
4454 int left, top, right, bottom;
4455 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4456 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
4457
4458 int cw, ch;
4459 m_gridWin->GetClientSize( &cw, &ch );
4460
4461 if ( top < 0 )
4462 {
4463 ypos = r.GetTop();
4464 }
4465 else if ( bottom > ch )
4466 {
4467 int h = r.GetHeight();
4468 ypos = r.GetTop();
4469 for ( i = row-1; i >= 0; i-- )
4470 {
4471 if ( h + m_rowHeights[i] > ch ) break;
4472
4473 h += m_rowHeights[i];
4474 ypos -= m_rowHeights[i];
4475 }
4476
4477 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
4478 // have rounding errors (this is important, because if we do, we
4479 // might not scroll at all and some cells won't be redrawn)
4480 ypos += GRID_SCROLL_LINE / 2;
4481 }
4482
4483 if ( left < 0 )
4484 {
4485 xpos = r.GetLeft();
4486 }
4487 else if ( right > cw )
4488 {
4489 int w = r.GetWidth();
4490 xpos = r.GetLeft();
4491 for ( i = col-1; i >= 0; i-- )
4492 {
4493 if ( w + m_colWidths[i] > cw ) break;
4494
4495 w += m_colWidths[i];
4496 xpos -= m_colWidths[i];
4497 }
4498
4499 // see comment for ypos above
4500 xpos += GRID_SCROLL_LINE / 2;
4501 }
4502
4503 if ( xpos != -1 || ypos != -1 )
4504 {
4505 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
4506 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
4507 Scroll( xpos, ypos );
4508 AdjustScrollbars();
4509 }
4510 }
4511 }
4512
4513
4514 //
4515 // ------ Grid cursor movement functions
4516 //
4517
4518 bool wxGrid::MoveCursorUp()
4519 {
4520 if ( m_currentCellCoords != wxGridNoCellCoords &&
4521 m_currentCellCoords.GetRow() > 0 )
4522 {
4523 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
4524 m_currentCellCoords.GetCol() );
4525
4526 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
4527 m_currentCellCoords.GetCol() );
4528
4529 return TRUE;
4530 }
4531
4532 return FALSE;
4533 }
4534
4535
4536 bool wxGrid::MoveCursorDown()
4537 {
4538 // TODO: allow for scrolling
4539 //
4540 if ( m_currentCellCoords != wxGridNoCellCoords &&
4541 m_currentCellCoords.GetRow() < m_numRows-1 )
4542 {
4543 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
4544 m_currentCellCoords.GetCol() );
4545
4546 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
4547 m_currentCellCoords.GetCol() );
4548
4549 return TRUE;
4550 }
4551
4552 return FALSE;
4553 }
4554
4555
4556 bool wxGrid::MoveCursorLeft()
4557 {
4558 if ( m_currentCellCoords != wxGridNoCellCoords &&
4559 m_currentCellCoords.GetCol() > 0 )
4560 {
4561 MakeCellVisible( m_currentCellCoords.GetRow(),
4562 m_currentCellCoords.GetCol() - 1 );
4563
4564 SetCurrentCell( m_currentCellCoords.GetRow(),
4565 m_currentCellCoords.GetCol() - 1 );
4566
4567 return TRUE;
4568 }
4569
4570 return FALSE;
4571 }
4572
4573
4574 bool wxGrid::MoveCursorRight()
4575 {
4576 if ( m_currentCellCoords != wxGridNoCellCoords &&
4577 m_currentCellCoords.GetCol() < m_numCols - 1 )
4578 {
4579 MakeCellVisible( m_currentCellCoords.GetRow(),
4580 m_currentCellCoords.GetCol() + 1 );
4581
4582 SetCurrentCell( m_currentCellCoords.GetRow(),
4583 m_currentCellCoords.GetCol() + 1 );
4584
4585 return TRUE;
4586 }
4587
4588 return FALSE;
4589 }
4590
4591
4592 bool wxGrid::MovePageUp()
4593 {
4594 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
4595
4596 int row = m_currentCellCoords.GetRow();
4597 if ( row > 0 )
4598 {
4599 int cw, ch;
4600 m_gridWin->GetClientSize( &cw, &ch );
4601
4602 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4603 int newRow = YToRow( y - ch + 1 );
4604 if ( newRow == -1 )
4605 {
4606 newRow = 0;
4607 }
4608 else if ( newRow == row )
4609 {
4610 newRow = row - 1;
4611 }
4612
4613 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4614 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
4615
4616 return TRUE;
4617 }
4618
4619 return FALSE;
4620 }
4621
4622 bool wxGrid::MovePageDown()
4623 {
4624 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
4625
4626 int row = m_currentCellCoords.GetRow();
4627 if ( row < m_numRows )
4628 {
4629 int cw, ch;
4630 m_gridWin->GetClientSize( &cw, &ch );
4631
4632 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4633 int newRow = YToRow( y + ch );
4634 if ( newRow == -1 )
4635 {
4636 newRow = m_numRows - 1;
4637 }
4638 else if ( newRow == row )
4639 {
4640 newRow = row + 1;
4641 }
4642
4643 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4644 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
4645
4646 return TRUE;
4647 }
4648
4649 return FALSE;
4650 }
4651
4652 bool wxGrid::MoveCursorUpBlock()
4653 {
4654 if ( m_table &&
4655 m_currentCellCoords != wxGridNoCellCoords &&
4656 m_currentCellCoords.GetRow() > 0 )
4657 {
4658 int row = m_currentCellCoords.GetRow();
4659 int col = m_currentCellCoords.GetCol();
4660
4661 if ( m_table->IsEmptyCell(row, col) )
4662 {
4663 // starting in an empty cell: find the next block of
4664 // non-empty cells
4665 //
4666 while ( row > 0 )
4667 {
4668 row-- ;
4669 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4670 }
4671 }
4672 else if ( m_table->IsEmptyCell(row-1, col) )
4673 {
4674 // starting at the top of a block: find the next block
4675 //
4676 row--;
4677 while ( row > 0 )
4678 {
4679 row-- ;
4680 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4681 }
4682 }
4683 else
4684 {
4685 // starting within a block: find the top of the block
4686 //
4687 while ( row > 0 )
4688 {
4689 row-- ;
4690 if ( m_table->IsEmptyCell(row, col) )
4691 {
4692 row++ ;
4693 break;
4694 }
4695 }
4696 }
4697
4698 MakeCellVisible( row, col );
4699 SetCurrentCell( row, col );
4700
4701 return TRUE;
4702 }
4703
4704 return FALSE;
4705 }
4706
4707 bool wxGrid::MoveCursorDownBlock()
4708 {
4709 if ( m_table &&
4710 m_currentCellCoords != wxGridNoCellCoords &&
4711 m_currentCellCoords.GetRow() < m_numRows-1 )
4712 {
4713 int row = m_currentCellCoords.GetRow();
4714 int col = m_currentCellCoords.GetCol();
4715
4716 if ( m_table->IsEmptyCell(row, col) )
4717 {
4718 // starting in an empty cell: find the next block of
4719 // non-empty cells
4720 //
4721 while ( row < m_numRows-1 )
4722 {
4723 row++ ;
4724 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4725 }
4726 }
4727 else if ( m_table->IsEmptyCell(row+1, col) )
4728 {
4729 // starting at the bottom of a block: find the next block
4730 //
4731 row++;
4732 while ( row < m_numRows-1 )
4733 {
4734 row++ ;
4735 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4736 }
4737 }
4738 else
4739 {
4740 // starting within a block: find the bottom of the block
4741 //
4742 while ( row < m_numRows-1 )
4743 {
4744 row++ ;
4745 if ( m_table->IsEmptyCell(row, col) )
4746 {
4747 row-- ;
4748 break;
4749 }
4750 }
4751 }
4752
4753 MakeCellVisible( row, col );
4754 SetCurrentCell( row, col );
4755
4756 return TRUE;
4757 }
4758
4759 return FALSE;
4760 }
4761
4762 bool wxGrid::MoveCursorLeftBlock()
4763 {
4764 if ( m_table &&
4765 m_currentCellCoords != wxGridNoCellCoords &&
4766 m_currentCellCoords.GetCol() > 0 )
4767 {
4768 int row = m_currentCellCoords.GetRow();
4769 int col = m_currentCellCoords.GetCol();
4770
4771 if ( m_table->IsEmptyCell(row, col) )
4772 {
4773 // starting in an empty cell: find the next block of
4774 // non-empty cells
4775 //
4776 while ( col > 0 )
4777 {
4778 col-- ;
4779 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4780 }
4781 }
4782 else if ( m_table->IsEmptyCell(row, col-1) )
4783 {
4784 // starting at the left of a block: find the next block
4785 //
4786 col--;
4787 while ( col > 0 )
4788 {
4789 col-- ;
4790 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4791 }
4792 }
4793 else
4794 {
4795 // starting within a block: find the left of the block
4796 //
4797 while ( col > 0 )
4798 {
4799 col-- ;
4800 if ( m_table->IsEmptyCell(row, col) )
4801 {
4802 col++ ;
4803 break;
4804 }
4805 }
4806 }
4807
4808 MakeCellVisible( row, col );
4809 SetCurrentCell( row, col );
4810
4811 return TRUE;
4812 }
4813
4814 return FALSE;
4815 }
4816
4817 bool wxGrid::MoveCursorRightBlock()
4818 {
4819 if ( m_table &&
4820 m_currentCellCoords != wxGridNoCellCoords &&
4821 m_currentCellCoords.GetCol() < m_numCols-1 )
4822 {
4823 int row = m_currentCellCoords.GetRow();
4824 int col = m_currentCellCoords.GetCol();
4825
4826 if ( m_table->IsEmptyCell(row, col) )
4827 {
4828 // starting in an empty cell: find the next block of
4829 // non-empty cells
4830 //
4831 while ( col < m_numCols-1 )
4832 {
4833 col++ ;
4834 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4835 }
4836 }
4837 else if ( m_table->IsEmptyCell(row, col+1) )
4838 {
4839 // starting at the right of a block: find the next block
4840 //
4841 col++;
4842 while ( col < m_numCols-1 )
4843 {
4844 col++ ;
4845 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4846 }
4847 }
4848 else
4849 {
4850 // starting within a block: find the right of the block
4851 //
4852 while ( col < m_numCols-1 )
4853 {
4854 col++ ;
4855 if ( m_table->IsEmptyCell(row, col) )
4856 {
4857 col-- ;
4858 break;
4859 }
4860 }
4861 }
4862
4863 MakeCellVisible( row, col );
4864 SetCurrentCell( row, col );
4865
4866 return TRUE;
4867 }
4868
4869 return FALSE;
4870 }
4871
4872
4873
4874 //
4875 // ------ Label values and formatting
4876 //
4877
4878 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
4879 {
4880 *horiz = m_rowLabelHorizAlign;
4881 *vert = m_rowLabelVertAlign;
4882 }
4883
4884 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
4885 {
4886 *horiz = m_colLabelHorizAlign;
4887 *vert = m_colLabelVertAlign;
4888 }
4889
4890 wxString wxGrid::GetRowLabelValue( int row )
4891 {
4892 if ( m_table )
4893 {
4894 return m_table->GetRowLabelValue( row );
4895 }
4896 else
4897 {
4898 wxString s;
4899 s << row;
4900 return s;
4901 }
4902 }
4903
4904 wxString wxGrid::GetColLabelValue( int col )
4905 {
4906 if ( m_table )
4907 {
4908 return m_table->GetColLabelValue( col );
4909 }
4910 else
4911 {
4912 wxString s;
4913 s << col;
4914 return s;
4915 }
4916 }
4917
4918
4919 void wxGrid::SetRowLabelSize( int width )
4920 {
4921 width = wxMax( width, 0 );
4922 if ( width != m_rowLabelWidth )
4923 {
4924 if ( width == 0 )
4925 {
4926 m_rowLabelWin->Show( FALSE );
4927 m_cornerLabelWin->Show( FALSE );
4928 }
4929 else if ( m_rowLabelWidth == 0 )
4930 {
4931 m_rowLabelWin->Show( TRUE );
4932 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
4933 }
4934
4935 m_rowLabelWidth = width;
4936 CalcWindowSizes();
4937 Refresh( TRUE );
4938 }
4939 }
4940
4941
4942 void wxGrid::SetColLabelSize( int height )
4943 {
4944 height = wxMax( height, 0 );
4945 if ( height != m_colLabelHeight )
4946 {
4947 if ( height == 0 )
4948 {
4949 m_colLabelWin->Show( FALSE );
4950 m_cornerLabelWin->Show( FALSE );
4951 }
4952 else if ( m_colLabelHeight == 0 )
4953 {
4954 m_colLabelWin->Show( TRUE );
4955 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
4956 }
4957
4958 m_colLabelHeight = height;
4959 CalcWindowSizes();
4960 Refresh( TRUE );
4961 }
4962 }
4963
4964
4965 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
4966 {
4967 if ( m_labelBackgroundColour != colour )
4968 {
4969 m_labelBackgroundColour = colour;
4970 m_rowLabelWin->SetBackgroundColour( colour );
4971 m_colLabelWin->SetBackgroundColour( colour );
4972 m_cornerLabelWin->SetBackgroundColour( colour );
4973
4974 if ( !GetBatchCount() )
4975 {
4976 m_rowLabelWin->Refresh();
4977 m_colLabelWin->Refresh();
4978 m_cornerLabelWin->Refresh();
4979 }
4980 }
4981 }
4982
4983 void wxGrid::SetLabelTextColour( const wxColour& colour )
4984 {
4985 if ( m_labelTextColour != colour )
4986 {
4987 m_labelTextColour = colour;
4988 if ( !GetBatchCount() )
4989 {
4990 m_rowLabelWin->Refresh();
4991 m_colLabelWin->Refresh();
4992 }
4993 }
4994 }
4995
4996 void wxGrid::SetLabelFont( const wxFont& font )
4997 {
4998 m_labelFont = font;
4999 if ( !GetBatchCount() )
5000 {
5001 m_rowLabelWin->Refresh();
5002 m_colLabelWin->Refresh();
5003 }
5004 }
5005
5006 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
5007 {
5008 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
5009 {
5010 m_rowLabelHorizAlign = horiz;
5011 }
5012
5013 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
5014 {
5015 m_rowLabelVertAlign = vert;
5016 }
5017
5018 if ( !GetBatchCount() )
5019 {
5020 m_rowLabelWin->Refresh();
5021 }
5022 }
5023
5024 void wxGrid::SetColLabelAlignment( int horiz, int vert )
5025 {
5026 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
5027 {
5028 m_colLabelHorizAlign = horiz;
5029 }
5030
5031 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
5032 {
5033 m_colLabelVertAlign = vert;
5034 }
5035
5036 if ( !GetBatchCount() )
5037 {
5038 m_colLabelWin->Refresh();
5039 }
5040 }
5041
5042 void wxGrid::SetRowLabelValue( int row, const wxString& s )
5043 {
5044 if ( m_table )
5045 {
5046 m_table->SetRowLabelValue( row, s );
5047 if ( !GetBatchCount() )
5048 {
5049 wxRect rect = CellToRect( row, 0);
5050 if ( rect.height > 0 )
5051 {
5052 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
5053 rect.x = m_left;
5054 rect.width = m_rowLabelWidth;
5055 m_rowLabelWin->Refresh( TRUE, &rect );
5056 }
5057 }
5058 }
5059 }
5060
5061 void wxGrid::SetColLabelValue( int col, const wxString& s )
5062 {
5063 if ( m_table )
5064 {
5065 m_table->SetColLabelValue( col, s );
5066 if ( !GetBatchCount() )
5067 {
5068 wxRect rect = CellToRect( 0, col );
5069 if ( rect.width > 0 )
5070 {
5071 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
5072 rect.y = m_top;
5073 rect.height = m_colLabelHeight;
5074 m_colLabelWin->Refresh( TRUE, &rect );
5075 }
5076 }
5077 }
5078 }
5079
5080 void wxGrid::SetGridLineColour( const wxColour& colour )
5081 {
5082 if ( m_gridLineColour != colour )
5083 {
5084 m_gridLineColour = colour;
5085
5086 wxClientDC dc( m_gridWin );
5087 PrepareDC( dc );
5088 DrawAllGridLines( dc, wxRegion() );
5089 }
5090 }
5091
5092 void wxGrid::EnableGridLines( bool enable )
5093 {
5094 if ( enable != m_gridLinesEnabled )
5095 {
5096 m_gridLinesEnabled = enable;
5097
5098 if ( !GetBatchCount() )
5099 {
5100 if ( enable )
5101 {
5102 wxClientDC dc( m_gridWin );
5103 PrepareDC( dc );
5104 DrawAllGridLines( dc, wxRegion() );
5105 }
5106 else
5107 {
5108 m_gridWin->Refresh();
5109 }
5110 }
5111 }
5112 }
5113
5114
5115 int wxGrid::GetDefaultRowSize()
5116 {
5117 return m_defaultRowHeight;
5118 }
5119
5120 int wxGrid::GetRowSize( int row )
5121 {
5122 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
5123
5124 return m_rowHeights[row];
5125 }
5126
5127 int wxGrid::GetDefaultColSize()
5128 {
5129 return m_defaultColWidth;
5130 }
5131
5132 int wxGrid::GetColSize( int col )
5133 {
5134 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
5135
5136 return m_colWidths[col];
5137 }
5138
5139 // ============================================================================
5140 // access to the grid attributes: each of them has a default value in the grid
5141 // itself and may be overidden on a per-cell basis
5142 // ============================================================================
5143
5144 // ----------------------------------------------------------------------------
5145 // setting default attributes
5146 // ----------------------------------------------------------------------------
5147
5148 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
5149 {
5150 m_defaultCellAttr->SetBackgroundColour(col);
5151 }
5152
5153 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
5154 {
5155 m_defaultCellAttr->SetTextColour(col);
5156 }
5157
5158 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
5159 {
5160 m_defaultCellAttr->SetAlignment(horiz, vert);
5161 }
5162
5163 void wxGrid::SetDefaultCellFont( const wxFont& font )
5164 {
5165 m_defaultCellAttr->SetFont(font);
5166 }
5167
5168 void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
5169 {
5170 m_defaultCellAttr->SetRenderer(renderer);
5171 }
5172
5173 // ----------------------------------------------------------------------------
5174 // access to the default attrbiutes
5175 // ----------------------------------------------------------------------------
5176
5177 wxColour wxGrid::GetDefaultCellBackgroundColour()
5178 {
5179 return m_defaultCellAttr->GetBackgroundColour();
5180 }
5181
5182 wxColour wxGrid::GetDefaultCellTextColour()
5183 {
5184 return m_defaultCellAttr->GetTextColour();
5185 }
5186
5187 wxFont wxGrid::GetDefaultCellFont()
5188 {
5189 return m_defaultCellAttr->GetFont();
5190 }
5191
5192 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
5193 {
5194 m_defaultCellAttr->GetAlignment(horiz, vert);
5195 }
5196
5197 wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
5198 {
5199 return m_defaultCellAttr->GetRenderer();
5200 }
5201
5202 // ----------------------------------------------------------------------------
5203 // access to cell attributes
5204 // ----------------------------------------------------------------------------
5205
5206 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
5207 {
5208 wxGridCellAttr *attr = GetCellAttr(row, col);
5209 wxColour colour = attr->GetBackgroundColour();
5210 attr->SafeDecRef();
5211 return colour;
5212 }
5213
5214 wxColour wxGrid::GetCellTextColour( int row, int col )
5215 {
5216 wxGridCellAttr *attr = GetCellAttr(row, col);
5217 wxColour colour = attr->GetTextColour();
5218 attr->SafeDecRef();
5219 return colour;
5220 }
5221
5222 wxFont wxGrid::GetCellFont( int row, int col )
5223 {
5224 wxGridCellAttr *attr = GetCellAttr(row, col);
5225 wxFont font = attr->GetFont();
5226 attr->SafeDecRef();
5227 return font;
5228 }
5229
5230 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
5231 {
5232 wxGridCellAttr *attr = GetCellAttr(row, col);
5233 attr->GetAlignment(horiz, vert);
5234 attr->SafeDecRef();
5235 }
5236
5237 wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
5238 {
5239 wxGridCellAttr* attr = GetCellAttr(row, col);
5240 wxGridCellRenderer* renderer = attr->GetRenderer();
5241 attr->DecRef();
5242 return renderer;
5243 }
5244
5245 // ----------------------------------------------------------------------------
5246 // attribute support: cache, automatic provider creation, ...
5247 // ----------------------------------------------------------------------------
5248
5249 bool wxGrid::CanHaveAttributes()
5250 {
5251 if ( !m_table )
5252 {
5253 return FALSE;
5254 }
5255
5256 // RD: Maybe m_table->CanHaveAttributes() would be better in case the
5257 // table is providing the attributes itself??? In which case
5258 // I don't think the grid should create a Provider object for the
5259 // table but the table should be smart enough to do that on its own.
5260 if ( !m_table->GetAttrProvider() )
5261 {
5262 // use the default attr provider by default
5263 // (another choice would be to just return FALSE thus forcing the user
5264 // to it himself)
5265 m_table->SetAttrProvider(new wxGridCellAttrProvider);
5266 }
5267
5268 return TRUE;
5269 }
5270
5271 void wxGrid::ClearAttrCache()
5272 {
5273 if ( m_attrCache.row != -1 )
5274 {
5275 m_attrCache.attr->SafeDecRef();
5276 m_attrCache.row = -1;
5277 }
5278 }
5279
5280 void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
5281 {
5282 wxGrid *self = (wxGrid *)this; // const_cast
5283
5284 self->ClearAttrCache();
5285 self->m_attrCache.row = row;
5286 self->m_attrCache.col = col;
5287 self->m_attrCache.attr = attr;
5288 attr->SafeIncRef();
5289 }
5290
5291 bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
5292 {
5293 if ( row == m_attrCache.row && col == m_attrCache.col )
5294 {
5295 *attr = m_attrCache.attr;
5296 (*attr)->SafeIncRef();
5297
5298 #ifdef DEBUG_ATTR_CACHE
5299 gs_nAttrCacheHits++;
5300 #endif
5301
5302 return TRUE;
5303 }
5304 else
5305 {
5306 #ifdef DEBUG_ATTR_CACHE
5307 gs_nAttrCacheMisses++;
5308 #endif
5309 return FALSE;
5310 }
5311 }
5312
5313 wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
5314 {
5315 wxGridCellAttr *attr;
5316 if ( !LookupAttr(row, col, &attr) )
5317 {
5318 attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
5319 CacheAttr(row, col, attr);
5320 }
5321 if (attr) {
5322 attr->SetDefAttr(m_defaultCellAttr);
5323 } else {
5324 attr = m_defaultCellAttr;
5325 attr->IncRef();
5326 }
5327
5328 return attr;
5329 }
5330
5331 wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
5332 {
5333 wxGridCellAttr *attr;
5334 if ( !LookupAttr(row, col, &attr) || !attr )
5335 {
5336 wxASSERT_MSG( m_table,
5337 _T("we may only be called if CanHaveAttributes() "
5338 "returned TRUE and then m_table should be !NULL") );
5339
5340 attr = m_table->GetAttr(row, col);
5341 if ( !attr )
5342 {
5343 attr = new wxGridCellAttr;
5344
5345 // artificially inc the ref count to match DecRef() in caller
5346 attr->IncRef();
5347
5348 m_table->SetAttr(attr, row, col);
5349 }
5350
5351 CacheAttr(row, col, attr);
5352 }
5353 attr->SetDefAttr(m_defaultCellAttr);
5354 return attr;
5355 }
5356
5357 // ----------------------------------------------------------------------------
5358 // setting cell attributes: this is forwarded to the table
5359 // ----------------------------------------------------------------------------
5360
5361 void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
5362 {
5363 if ( CanHaveAttributes() )
5364 {
5365 m_table->SetRowAttr(attr, row);
5366 }
5367 else
5368 {
5369 attr->SafeDecRef();
5370 }
5371 }
5372
5373 void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
5374 {
5375 if ( CanHaveAttributes() )
5376 {
5377 m_table->SetColAttr(attr, col);
5378 }
5379 else
5380 {
5381 attr->SafeDecRef();
5382 }
5383 }
5384
5385 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
5386 {
5387 if ( CanHaveAttributes() )
5388 {
5389 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5390 attr->SetBackgroundColour(colour);
5391 attr->DecRef();
5392 }
5393 }
5394
5395 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
5396 {
5397 if ( CanHaveAttributes() )
5398 {
5399 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5400 attr->SetTextColour(colour);
5401 attr->DecRef();
5402 }
5403 }
5404
5405 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
5406 {
5407 if ( CanHaveAttributes() )
5408 {
5409 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5410 attr->SetFont(font);
5411 attr->DecRef();
5412 }
5413 }
5414
5415 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
5416 {
5417 if ( CanHaveAttributes() )
5418 {
5419 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5420 attr->SetAlignment(horiz, vert);
5421 attr->DecRef();
5422 }
5423 }
5424
5425 void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
5426 {
5427 if ( CanHaveAttributes() )
5428 {
5429 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5430 attr->SetRenderer(renderer);
5431 attr->DecRef();
5432 }
5433 }
5434
5435 // ----------------------------------------------------------------------------
5436 // row/col size
5437 // ----------------------------------------------------------------------------
5438
5439 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
5440 {
5441 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
5442
5443 if ( resizeExistingRows )
5444 {
5445 int row;
5446 int bottom = 0;
5447 for ( row = 0; row < m_numRows; row++ )
5448 {
5449 m_rowHeights[row] = m_defaultRowHeight;
5450 bottom += m_defaultRowHeight;
5451 m_rowBottoms[row] = bottom;
5452 }
5453 CalcDimensions();
5454 }
5455 }
5456
5457 void wxGrid::SetRowSize( int row, int height )
5458 {
5459 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
5460
5461 int i;
5462
5463 int h = wxMax( 0, height );
5464 int diff = h - m_rowHeights[row];
5465
5466 m_rowHeights[row] = h;
5467 for ( i = row; i < m_numRows; i++ )
5468 {
5469 m_rowBottoms[i] += diff;
5470 }
5471 CalcDimensions();
5472 }
5473
5474 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
5475 {
5476 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
5477
5478 if ( resizeExistingCols )
5479 {
5480 int col;
5481 int right = 0;
5482 for ( col = 0; col < m_numCols; col++ )
5483 {
5484 m_colWidths[col] = m_defaultColWidth;
5485 right += m_defaultColWidth;
5486 m_colRights[col] = right;
5487 }
5488 CalcDimensions();
5489 }
5490 }
5491
5492 void wxGrid::SetColSize( int col, int width )
5493 {
5494 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
5495
5496 int i;
5497
5498 int w = wxMax( 0, width );
5499 int diff = w - m_colWidths[col];
5500 m_colWidths[col] = w;
5501
5502 for ( i = col; i < m_numCols; i++ )
5503 {
5504 m_colRights[i] += diff;
5505 }
5506 CalcDimensions();
5507 }
5508
5509
5510 //
5511 // ------ cell value accessor functions
5512 //
5513
5514 void wxGrid::SetCellValue( int row, int col, const wxString& s )
5515 {
5516 if ( m_table )
5517 {
5518 m_table->SetValue( row, col, s.c_str() );
5519 if ( !GetBatchCount() )
5520 {
5521 wxClientDC dc( m_gridWin );
5522 PrepareDC( dc );
5523 DrawCell( dc, wxGridCellCoords(row, col) );
5524 }
5525
5526 #if 0 // TODO: edit in place
5527
5528 if ( m_currentCellCoords.GetRow() == row &&
5529 m_currentCellCoords.GetCol() == col )
5530 {
5531 SetEditControlValue( s );
5532 }
5533 #endif
5534
5535 }
5536 }
5537
5538
5539 //
5540 // ------ Block, row and col selection
5541 //
5542
5543 void wxGrid::SelectRow( int row, bool addToSelected )
5544 {
5545 wxRect r;
5546
5547 if ( IsSelection() && addToSelected )
5548 {
5549 wxRect rect[4];
5550 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5551 int i;
5552
5553 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5554 wxCoord oldTop = m_selectedTopLeft.GetRow();
5555 wxCoord oldRight = m_selectedBottomRight.GetCol();
5556 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5557
5558 if ( oldTop > row )
5559 {
5560 need_refresh[0] = TRUE;
5561 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
5562 wxGridCellCoords ( oldTop - 1,
5563 m_numCols - 1 ) );
5564 m_selectedTopLeft.SetRow( row );
5565 }
5566
5567 if ( oldLeft > 0 )
5568 {
5569 need_refresh[1] = TRUE;
5570 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
5571 wxGridCellCoords ( oldBottom,
5572 oldLeft - 1 ) );
5573
5574 m_selectedTopLeft.SetCol( 0 );
5575 }
5576
5577 if ( oldBottom < row )
5578 {
5579 need_refresh[2] = TRUE;
5580 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
5581 wxGridCellCoords ( row,
5582 m_numCols - 1 ) );
5583 m_selectedBottomRight.SetRow( row );
5584 }
5585
5586 if ( oldRight < m_numCols - 1 )
5587 {
5588 need_refresh[3] = TRUE;
5589 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
5590 oldRight + 1 ),
5591 wxGridCellCoords ( oldBottom,
5592 m_numCols - 1 ) );
5593 m_selectedBottomRight.SetCol( m_numCols - 1 );
5594 }
5595
5596 for (i = 0; i < 4; i++ )
5597 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5598 m_gridWin->Refresh( FALSE, &(rect[i]) );
5599 }
5600 else
5601 {
5602 r = SelectionToDeviceRect();
5603 ClearSelection();
5604 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
5605
5606 m_selectedTopLeft.Set( row, 0 );
5607 m_selectedBottomRight.Set( row, m_numCols-1 );
5608 r = SelectionToDeviceRect();
5609 m_gridWin->Refresh( FALSE, &r );
5610 }
5611
5612 wxGridRangeSelectEvent gridEvt( GetId(),
5613 EVT_GRID_RANGE_SELECT,
5614 this,
5615 m_selectedTopLeft,
5616 m_selectedBottomRight );
5617
5618 GetEventHandler()->ProcessEvent(gridEvt);
5619 }
5620
5621
5622 void wxGrid::SelectCol( int col, bool addToSelected )
5623 {
5624 if ( IsSelection() && addToSelected )
5625 {
5626 wxRect rect[4];
5627 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5628 int i;
5629
5630 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5631 wxCoord oldTop = m_selectedTopLeft.GetRow();
5632 wxCoord oldRight = m_selectedBottomRight.GetCol();
5633 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5634
5635 if ( oldLeft > col )
5636 {
5637 need_refresh[0] = TRUE;
5638 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
5639 wxGridCellCoords ( m_numRows - 1,
5640 oldLeft - 1 ) );
5641 m_selectedTopLeft.SetCol( col );
5642 }
5643
5644 if ( oldTop > 0 )
5645 {
5646 need_refresh[1] = TRUE;
5647 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
5648 wxGridCellCoords ( oldTop - 1,
5649 oldRight ) );
5650 m_selectedTopLeft.SetRow( 0 );
5651 }
5652
5653 if ( oldRight < col )
5654 {
5655 need_refresh[2] = TRUE;
5656 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
5657 wxGridCellCoords ( m_numRows - 1,
5658 col ) );
5659 m_selectedBottomRight.SetCol( col );
5660 }
5661
5662 if ( oldBottom < m_numRows - 1 )
5663 {
5664 need_refresh[3] = TRUE;
5665 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
5666 oldLeft ),
5667 wxGridCellCoords ( m_numRows - 1,
5668 oldRight ) );
5669 m_selectedBottomRight.SetRow( m_numRows - 1 );
5670 }
5671
5672 for (i = 0; i < 4; i++ )
5673 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5674 m_gridWin->Refresh( FALSE, &(rect[i]) );
5675 }
5676 else
5677 {
5678 wxRect r;
5679
5680 r = SelectionToDeviceRect();
5681 ClearSelection();
5682 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
5683
5684 m_selectedTopLeft.Set( 0, col );
5685 m_selectedBottomRight.Set( m_numRows-1, col );
5686 r = SelectionToDeviceRect();
5687 m_gridWin->Refresh( FALSE, &r );
5688 }
5689
5690 wxGridRangeSelectEvent gridEvt( GetId(),
5691 EVT_GRID_RANGE_SELECT,
5692 this,
5693 m_selectedTopLeft,
5694 m_selectedBottomRight );
5695
5696 GetEventHandler()->ProcessEvent(gridEvt);
5697 }
5698
5699
5700 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
5701 {
5702 int temp;
5703 wxGridCellCoords updateTopLeft, updateBottomRight;
5704
5705 if ( topRow > bottomRow )
5706 {
5707 temp = topRow;
5708 topRow = bottomRow;
5709 bottomRow = temp;
5710 }
5711
5712 if ( leftCol > rightCol )
5713 {
5714 temp = leftCol;
5715 leftCol = rightCol;
5716 rightCol = temp;
5717 }
5718
5719 updateTopLeft = wxGridCellCoords( topRow, leftCol );
5720 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
5721
5722 if ( m_selectedTopLeft != updateTopLeft ||
5723 m_selectedBottomRight != updateBottomRight )
5724 {
5725 // Compute two optimal update rectangles:
5726 // Either one rectangle is a real subset of the
5727 // other, or they are (almost) disjoint!
5728 wxRect rect[4];
5729 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5730 int i;
5731
5732 // Store intermediate values
5733 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5734 wxCoord oldTop = m_selectedTopLeft.GetRow();
5735 wxCoord oldRight = m_selectedBottomRight.GetCol();
5736 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5737
5738 // Determine the outer/inner coordinates.
5739 if (oldLeft > leftCol)
5740 {
5741 temp = oldLeft;
5742 oldLeft = leftCol;
5743 leftCol = temp;
5744 }
5745 if (oldTop > topRow )
5746 {
5747 temp = oldTop;
5748 oldTop = topRow;
5749 topRow = temp;
5750 }
5751 if (oldRight < rightCol )
5752 {
5753 temp = oldRight;
5754 oldRight = rightCol;
5755 rightCol = temp;
5756 }
5757 if (oldBottom < bottomRow)
5758 {
5759 temp = oldBottom;
5760 oldBottom = bottomRow;
5761 bottomRow = temp;
5762 }
5763
5764 // Now, either the stuff marked old is the outer
5765 // rectangle or we don't have a situation where one
5766 // is contained in the other.
5767
5768 if ( oldLeft < leftCol )
5769 {
5770 need_refresh[0] = TRUE;
5771 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5772 oldLeft ),
5773 wxGridCellCoords ( oldBottom,
5774 leftCol - 1 ) );
5775 }
5776
5777 if ( oldTop < topRow )
5778 {
5779 need_refresh[1] = TRUE;
5780 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5781 leftCol ),
5782 wxGridCellCoords ( topRow - 1,
5783 rightCol ) );
5784 }
5785
5786 if ( oldRight > rightCol )
5787 {
5788 need_refresh[2] = TRUE;
5789 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5790 rightCol + 1 ),
5791 wxGridCellCoords ( oldBottom,
5792 oldRight ) );
5793 }
5794
5795 if ( oldBottom > bottomRow )
5796 {
5797 need_refresh[3] = TRUE;
5798 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
5799 leftCol ),
5800 wxGridCellCoords ( oldBottom,
5801 rightCol ) );
5802 }
5803
5804
5805 // Change Selection
5806 m_selectedTopLeft = updateTopLeft;
5807 m_selectedBottomRight = updateBottomRight;
5808
5809 // various Refresh() calls
5810 for (i = 0; i < 4; i++ )
5811 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5812 m_gridWin->Refresh( FALSE, &(rect[i]) );
5813 }
5814
5815 // only generate an event if the block is not being selected by
5816 // dragging the mouse (in which case the event will be generated in
5817 // the mouse event handler)
5818 if ( !m_isDragging )
5819 {
5820 wxGridRangeSelectEvent gridEvt( GetId(),
5821 EVT_GRID_RANGE_SELECT,
5822 this,
5823 m_selectedTopLeft,
5824 m_selectedBottomRight );
5825
5826 GetEventHandler()->ProcessEvent(gridEvt);
5827 }
5828 }
5829
5830 void wxGrid::SelectAll()
5831 {
5832 m_selectedTopLeft.Set( 0, 0 );
5833 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
5834
5835 m_gridWin->Refresh();
5836 }
5837
5838
5839 void wxGrid::ClearSelection()
5840 {
5841 m_selectedTopLeft = wxGridNoCellCoords;
5842 m_selectedBottomRight = wxGridNoCellCoords;
5843 }
5844
5845
5846 // This function returns the rectangle that encloses the given block
5847 // in device coords clipped to the client size of the grid window.
5848 //
5849 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
5850 const wxGridCellCoords &bottomRight )
5851 {
5852 wxRect rect( wxGridNoCellRect );
5853 wxRect cellRect;
5854
5855 cellRect = CellToRect( topLeft );
5856 if ( cellRect != wxGridNoCellRect )
5857 {
5858 rect = cellRect;
5859 }
5860 else
5861 {
5862 rect = wxRect( 0, 0, 0, 0 );
5863 }
5864
5865 cellRect = CellToRect( bottomRight );
5866 if ( cellRect != wxGridNoCellRect )
5867 {
5868 rect += cellRect;
5869 }
5870 else
5871 {
5872 return wxGridNoCellRect;
5873 }
5874
5875 // convert to scrolled coords
5876 //
5877 int left, top, right, bottom;
5878 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
5879 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
5880
5881 int cw, ch;
5882 m_gridWin->GetClientSize( &cw, &ch );
5883
5884 rect.SetLeft( wxMax(0, left) );
5885 rect.SetTop( wxMax(0, top) );
5886 rect.SetRight( wxMin(cw, right) );
5887 rect.SetBottom( wxMin(ch, bottom) );
5888
5889 return rect;
5890 }
5891
5892
5893
5894 //
5895 // ------ Grid event classes
5896 //
5897
5898 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
5899
5900 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
5901 int row, int col, int x, int y,
5902 bool control, bool shift, bool alt, bool meta )
5903 : wxNotifyEvent( type, id )
5904 {
5905 m_row = row;
5906 m_col = col;
5907 m_x = x;
5908 m_y = y;
5909 m_control = control;
5910 m_shift = shift;
5911 m_alt = alt;
5912 m_meta = meta;
5913
5914 SetEventObject(obj);
5915 }
5916
5917
5918 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
5919
5920 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
5921 int rowOrCol, int x, int y,
5922 bool control, bool shift, bool alt, bool meta )
5923 : wxNotifyEvent( type, id )
5924 {
5925 m_rowOrCol = rowOrCol;
5926 m_x = x;
5927 m_y = y;
5928 m_control = control;
5929 m_shift = shift;
5930 m_alt = alt;
5931 m_meta = meta;
5932
5933 SetEventObject(obj);
5934 }
5935
5936
5937 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
5938
5939 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
5940 const wxGridCellCoords& topLeft,
5941 const wxGridCellCoords& bottomRight,
5942 bool control, bool shift, bool alt, bool meta )
5943 : wxNotifyEvent( type, id )
5944 {
5945 m_topLeft = topLeft;
5946 m_bottomRight = bottomRight;
5947 m_control = control;
5948 m_shift = shift;
5949 m_alt = alt;
5950 m_meta = meta;
5951
5952 SetEventObject(obj);
5953 }
5954
5955
5956 #endif // ifndef wxUSE_NEW_GRID
5957