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