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