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