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