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