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