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