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