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