]> git.saurik.com Git - wxWidgets.git/blame - src/generic/grid.cpp
Const casting fix for Vis C.
[wxWidgets.git] / src / generic / grid.cpp
CommitLineData
2796cce3 1///////////////////////////////////////////////////////////////////////////
d16c04bb 2// Name: generic/grid.cpp
f85afd4e
MB
3// Purpose: wxGrid and related classes
4// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
5// Modified by:
6// Created: 1/08/1999
7// RCS-ID: $Id$
8// Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
758cbedf
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
f85afd4e
MB
20#ifdef __GNUG__
21 #pragma implementation "grid.h"
22#endif
23
f6bcfd97 24// For compilers that support precompilatixon, includes "wx/wx.h".
4d85bcd1
JS
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"
4ee5fc9c 44 #include "wx/combobox.h"
816be743 45 #include "wx/valtext.h"
f85afd4e
MB
46#endif
47
cb5df486 48#include "wx/textfile.h"
816be743 49#include "wx/spinctrl.h"
c4608a8a 50#include "wx/tokenzr.h"
6d004f67 51
07296f0b 52#include "wx/grid.h"
b5808881 53#include "wx/generic/gridsel.h"
07296f0b 54
0b7e6e7d
SN
55#if defined(__WXMOTIF__)
56 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
c78b3acd 57#else
0b7e6e7d 58 #define WXUNUSED_MOTIF(identifier) identifier
c78b3acd
SN
59#endif
60
61#if defined(__WXGTK__)
62 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
63#else
64 #define WXUNUSED_GTK(identifier) identifier
65#endif
66
3f8e5072
JS
67// Required for wxIs... functions
68#include <ctype.h>
69
b99be8fb 70// ----------------------------------------------------------------------------
758cbedf 71// array classes
b99be8fb
VZ
72// ----------------------------------------------------------------------------
73
f6bcfd97 74WX_DEFINE_EXPORTED_ARRAY(wxGridCellAttr *, wxArrayAttrs);
758cbedf 75
b99be8fb
VZ
76struct wxGridCellWithAttr
77{
2e9a6788
VZ
78 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
79 : coords(row, col), attr(attr_)
b99be8fb
VZ
80 {
81 }
82
2e9a6788
VZ
83 ~wxGridCellWithAttr()
84 {
85 attr->DecRef();
86 }
87
b99be8fb 88 wxGridCellCoords coords;
2e9a6788 89 wxGridCellAttr *attr;
b99be8fb
VZ
90};
91
f6bcfd97 92WX_DECLARE_EXPORTED_OBJARRAY(wxGridCellWithAttr, wxGridCellWithAttrArray);
b99be8fb
VZ
93
94#include "wx/arrimpl.cpp"
95
96WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
97WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
98
0f442030
RR
99// ----------------------------------------------------------------------------
100// events
101// ----------------------------------------------------------------------------
102
2e4df4bf
VZ
103DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK)
104DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK)
105DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK)
106DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK)
107DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK)
108DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK)
109DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK)
110DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK)
111DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE)
112DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE)
113DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT)
114DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE)
115DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL)
116DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN)
117DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN)
0f442030 118
b99be8fb
VZ
119// ----------------------------------------------------------------------------
120// private classes
121// ----------------------------------------------------------------------------
122
123class WXDLLEXPORT wxGridRowLabelWindow : public wxWindow
124{
125public:
126 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
127 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
128 const wxPoint &pos, const wxSize &size );
129
130private:
131 wxGrid *m_owner;
132
133 void OnPaint( wxPaintEvent& event );
134 void OnMouseEvent( wxMouseEvent& event );
135 void OnKeyDown( wxKeyEvent& event );
f6bcfd97 136 void OnKeyUp( wxKeyEvent& );
b99be8fb
VZ
137
138 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
139 DECLARE_EVENT_TABLE()
140};
141
142
143class WXDLLEXPORT wxGridColLabelWindow : public wxWindow
144{
145public:
146 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
147 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
148 const wxPoint &pos, const wxSize &size );
149
150private:
151 wxGrid *m_owner;
152
153 void OnPaint( wxPaintEvent &event );
154 void OnMouseEvent( wxMouseEvent& event );
155 void OnKeyDown( wxKeyEvent& event );
f6bcfd97 156 void OnKeyUp( wxKeyEvent& );
b99be8fb
VZ
157
158 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
159 DECLARE_EVENT_TABLE()
160};
161
162
163class WXDLLEXPORT wxGridCornerLabelWindow : public wxWindow
164{
165public:
166 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
167 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
168 const wxPoint &pos, const wxSize &size );
169
170private:
171 wxGrid *m_owner;
172
173 void OnMouseEvent( wxMouseEvent& event );
174 void OnKeyDown( wxKeyEvent& event );
f6bcfd97 175 void OnKeyUp( wxKeyEvent& );
b99be8fb
VZ
176 void OnPaint( wxPaintEvent& event );
177
178 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
179 DECLARE_EVENT_TABLE()
180};
181
182class WXDLLEXPORT wxGridWindow : public wxPanel
183{
184public:
185 wxGridWindow()
186 {
187 m_owner = (wxGrid *)NULL;
188 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
189 m_colLabelWin = (wxGridColLabelWindow *)NULL;
190 }
191
192 wxGridWindow( wxGrid *parent,
193 wxGridRowLabelWindow *rowLblWin,
194 wxGridColLabelWindow *colLblWin,
195 wxWindowID id, const wxPoint &pos, const wxSize &size );
196 ~wxGridWindow();
197
198 void ScrollWindow( int dx, int dy, const wxRect *rect );
199
200private:
201 wxGrid *m_owner;
202 wxGridRowLabelWindow *m_rowLabelWin;
203 wxGridColLabelWindow *m_colLabelWin;
204
205 void OnPaint( wxPaintEvent &event );
206 void OnMouseEvent( wxMouseEvent& event );
207 void OnKeyDown( wxKeyEvent& );
f6bcfd97 208 void OnKeyUp( wxKeyEvent& );
2796cce3
RD
209 void OnEraseBackground( wxEraseEvent& );
210
b99be8fb
VZ
211
212 DECLARE_DYNAMIC_CLASS(wxGridWindow)
213 DECLARE_EVENT_TABLE()
214};
215
2796cce3
RD
216
217
218class wxGridCellEditorEvtHandler : public wxEvtHandler
219{
220public:
221 wxGridCellEditorEvtHandler()
222 : m_grid(0), m_editor(0)
223 { }
224 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
225 : m_grid(grid), m_editor(editor)
226 { }
227
228 void OnKeyDown(wxKeyEvent& event);
fb0de762 229 void OnChar(wxKeyEvent& event);
2796cce3
RD
230
231private:
232 wxGrid* m_grid;
233 wxGridCellEditor* m_editor;
234 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
235 DECLARE_EVENT_TABLE()
236};
237
238
239IMPLEMENT_DYNAMIC_CLASS( wxGridCellEditorEvtHandler, wxEvtHandler )
240BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
241 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
fb0de762 242 EVT_CHAR( wxGridCellEditorEvtHandler::OnChar )
2796cce3
RD
243END_EVENT_TABLE()
244
245
246
758cbedf 247// ----------------------------------------------------------------------------
b99be8fb 248// the internal data representation used by wxGridCellAttrProvider
758cbedf
VZ
249// ----------------------------------------------------------------------------
250
251// this class stores attributes set for cells
252class WXDLLEXPORT wxGridCellAttrData
b99be8fb
VZ
253{
254public:
2e9a6788 255 void SetAttr(wxGridCellAttr *attr, int row, int col);
b99be8fb 256 wxGridCellAttr *GetAttr(int row, int col) const;
4d60017a
SN
257 void UpdateAttrRows( size_t pos, int numRows );
258 void UpdateAttrCols( size_t pos, int numCols );
b99be8fb
VZ
259
260private:
261 // searches for the attr for given cell, returns wxNOT_FOUND if not found
262 int FindIndex(int row, int col) const;
263
264 wxGridCellWithAttrArray m_attrs;
265};
266
758cbedf
VZ
267// this class stores attributes set for rows or columns
268class WXDLLEXPORT wxGridRowOrColAttrData
269{
270public:
ee6694a7
VZ
271 // empty ctor to suppress warnings
272 wxGridRowOrColAttrData() { }
758cbedf
VZ
273 ~wxGridRowOrColAttrData();
274
275 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
276 wxGridCellAttr *GetAttr(int rowOrCol) const;
4d60017a 277 void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols );
758cbedf
VZ
278
279private:
280 wxArrayInt m_rowsOrCols;
281 wxArrayAttrs m_attrs;
282};
283
284// NB: this is just a wrapper around 3 objects: one which stores cell
285// attributes, and 2 others for row/col ones
286class WXDLLEXPORT wxGridCellAttrProviderData
287{
288public:
289 wxGridCellAttrData m_cellAttrs;
290 wxGridRowOrColAttrData m_rowAttrs,
291 m_colAttrs;
292};
293
f2d76237
RD
294
295// ----------------------------------------------------------------------------
296// data structures used for the data type registry
297// ----------------------------------------------------------------------------
298
b94ae1ea
VZ
299struct wxGridDataTypeInfo
300{
f2d76237
RD
301 wxGridDataTypeInfo(const wxString& typeName,
302 wxGridCellRenderer* renderer,
303 wxGridCellEditor* editor)
304 : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
305 { }
306
39bcce60
VZ
307 ~wxGridDataTypeInfo()
308 {
309 wxSafeDecRef(m_renderer);
310 wxSafeDecRef(m_editor);
311 }
f2d76237
RD
312
313 wxString m_typeName;
314 wxGridCellRenderer* m_renderer;
315 wxGridCellEditor* m_editor;
316};
317
318
f6bcfd97 319WX_DEFINE_EXPORTED_ARRAY(wxGridDataTypeInfo*, wxGridDataTypeInfoArray);
f2d76237
RD
320
321
b94ae1ea
VZ
322class WXDLLEXPORT wxGridTypeRegistry
323{
f2d76237 324public:
c78b3acd 325 wxGridTypeRegistry() {}
f2d76237 326 ~wxGridTypeRegistry();
b94ae1ea 327
f2d76237
RD
328 void RegisterDataType(const wxString& typeName,
329 wxGridCellRenderer* renderer,
330 wxGridCellEditor* editor);
c4608a8a
VZ
331
332 // find one of already registered data types
333 int FindRegisteredDataType(const wxString& typeName);
334
335 // try to FindRegisteredDataType(), if this fails and typeName is one of
336 // standard typenames, register it and return its index
f2d76237 337 int FindDataType(const wxString& typeName);
c4608a8a
VZ
338
339 // try to FindDataType(), if it fails see if it is not one of already
340 // registered data types with some params in which case clone the
341 // registered data type and set params for it
342 int FindOrCloneDataType(const wxString& typeName);
343
f2d76237
RD
344 wxGridCellRenderer* GetRenderer(int index);
345 wxGridCellEditor* GetEditor(int index);
346
347private:
348 wxGridDataTypeInfoArray m_typeinfo;
349};
350
b99be8fb
VZ
351// ----------------------------------------------------------------------------
352// conditional compilation
353// ----------------------------------------------------------------------------
354
9496deb5
MB
355#ifndef WXGRID_DRAW_LINES
356#define WXGRID_DRAW_LINES 1
796df70a
SN
357#endif
358
0a976765
VZ
359// ----------------------------------------------------------------------------
360// globals
361// ----------------------------------------------------------------------------
362
363//#define DEBUG_ATTR_CACHE
364#ifdef DEBUG_ATTR_CACHE
365 static size_t gs_nAttrCacheHits = 0;
366 static size_t gs_nAttrCacheMisses = 0;
367#endif // DEBUG_ATTR_CACHE
f85afd4e 368
43947979
VZ
369// ----------------------------------------------------------------------------
370// constants
371// ----------------------------------------------------------------------------
372
f85afd4e
MB
373wxGridCellCoords wxGridNoCellCoords( -1, -1 );
374wxRect wxGridNoCellRect( -1, -1, -1, -1 );
375
f0102d2a 376// scroll line size
faec5a43
SN
377// TODO: this doesn't work at all, grid cells have different sizes and approx
378// calculations don't work as because of the size mismatch scrollbars
379// sometimes fail to be shown when they should be or vice versa
380static const size_t GRID_SCROLL_LINE = 1;
f85afd4e 381
43947979
VZ
382// the size of hash tables used a bit everywhere (the max number of elements
383// in these hash tables is the number of rows/columns)
384static const int GRID_HASH_SIZE = 100;
385
ab79958a
VZ
386// ============================================================================
387// implementation
388// ============================================================================
389
2796cce3
RD
390// ----------------------------------------------------------------------------
391// wxGridCellEditor
392// ----------------------------------------------------------------------------
393
394wxGridCellEditor::wxGridCellEditor()
395{
396 m_control = NULL;
397}
398
399
400wxGridCellEditor::~wxGridCellEditor()
401{
402 Destroy();
403}
404
508011ce
VZ
405void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
406 wxWindowID WXUNUSED(id),
407 wxEvtHandler* evtHandler)
408{
189d0213 409 if ( evtHandler )
508011ce
VZ
410 m_control->PushEventHandler(evtHandler);
411}
2796cce3 412
189d0213
VZ
413void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
414 wxGridCellAttr *attr)
415{
416 // erase the background because we might not fill the cell
417 wxClientDC dc(m_control->GetParent());
418 dc.SetPen(*wxTRANSPARENT_PEN);
419 dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
420 dc.DrawRectangle(rectCell);
421
422 // redraw the control we just painted over
423 m_control->Refresh();
424}
425
2796cce3
RD
426void wxGridCellEditor::Destroy()
427{
508011ce
VZ
428 if (m_control)
429 {
b94ae1ea
VZ
430 m_control->PopEventHandler(TRUE /* delete it*/);
431
2796cce3
RD
432 m_control->Destroy();
433 m_control = NULL;
434 }
435}
436
3da93aae 437void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
2796cce3
RD
438{
439 wxASSERT_MSG(m_control,
440 wxT("The wxGridCellEditor must be Created first!"));
441 m_control->Show(show);
3da93aae
VZ
442
443 if ( show )
444 {
445 // set the colours/fonts if we have any
446 if ( attr )
447 {
f2d76237
RD
448 m_colFgOld = m_control->GetForegroundColour();
449 m_control->SetForegroundColour(attr->GetTextColour());
3da93aae 450
f2d76237
RD
451 m_colBgOld = m_control->GetBackgroundColour();
452 m_control->SetBackgroundColour(attr->GetBackgroundColour());
3da93aae 453
f2d76237
RD
454 m_fontOld = m_control->GetFont();
455 m_control->SetFont(attr->GetFont());
3da93aae
VZ
456
457 // can't do anything more in the base class version, the other
458 // attributes may only be used by the derived classes
459 }
460 }
461 else
462 {
463 // restore the standard colours fonts
464 if ( m_colFgOld.Ok() )
465 {
466 m_control->SetForegroundColour(m_colFgOld);
467 m_colFgOld = wxNullColour;
468 }
469
470 if ( m_colBgOld.Ok() )
471 {
472 m_control->SetBackgroundColour(m_colBgOld);
473 m_colBgOld = wxNullColour;
474 }
475
476 if ( m_fontOld.Ok() )
477 {
478 m_control->SetFont(m_fontOld);
479 m_fontOld = wxNullFont;
480 }
481 }
2796cce3
RD
482}
483
484void wxGridCellEditor::SetSize(const wxRect& rect)
485{
486 wxASSERT_MSG(m_control,
487 wxT("The wxGridCellEditor must be Created first!"));
28a77bc4 488 m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
2796cce3
RD
489}
490
491void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
492{
493 event.Skip();
494}
495
f6bcfd97
BP
496bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
497{
498 // accept the simple key presses, not anything with Ctrl/Alt/Meta
a4f7bf58 499 return !(event.ControlDown() || event.AltDown());
f6bcfd97 500}
2796cce3 501
2c9a89e0
RD
502void wxGridCellEditor::StartingKey(wxKeyEvent& event)
503{
e195a54c
VZ
504 event.Skip();
505}
2c9a89e0 506
e195a54c
VZ
507void wxGridCellEditor::StartingClick()
508{
b54ba671 509}
2c9a89e0 510
b54ba671
VZ
511// ----------------------------------------------------------------------------
512// wxGridCellTextEditor
513// ----------------------------------------------------------------------------
2c9a89e0 514
2796cce3
RD
515wxGridCellTextEditor::wxGridCellTextEditor()
516{
c4608a8a 517 m_maxChars = 0;
2796cce3
RD
518}
519
520void wxGridCellTextEditor::Create(wxWindow* parent,
521 wxWindowID id,
2796cce3
RD
522 wxEvtHandler* evtHandler)
523{
508011ce 524 m_control = new wxTextCtrl(parent, id, wxEmptyString,
2c9a89e0 525 wxDefaultPosition, wxDefaultSize
2796cce3 526#if defined(__WXMSW__)
84912ef8
RD
527 , wxTE_PROCESS_TAB | wxTE_MULTILINE |
528 wxTE_NO_VSCROLL | wxTE_AUTO_SCROLL
2796cce3 529#endif
508011ce 530 );
2796cce3 531
c4608a8a
VZ
532 // TODO: use m_maxChars
533
508011ce 534 wxGridCellEditor::Create(parent, id, evtHandler);
2796cce3
RD
535}
536
189d0213
VZ
537void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
538 wxGridCellAttr * WXUNUSED(attr))
539{
540 // as we fill the entire client area, don't do anything here to minimize
541 // flicker
542}
2796cce3 543
99306db2
VZ
544void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
545{
546 wxRect rect(rectOrig);
547
548 // Make the edit control large enough to allow for internal
549 // margins
550 //
551 // TODO: remove this if the text ctrl sizing is improved esp. for
552 // unix
553 //
554#if defined(__WXGTK__)
b0e282b3
RR
555 if (rect.x != 0)
556 {
557 rect.x += 1;
558 rect.y += 1;
559 rect.width -= 1;
560 rect.height -= 1;
561 }
99306db2 562#else // !GTK
cb105ad4 563 int extra_x = ( rect.x > 2 )? 2 : 1;
84912ef8
RD
564
565// MB: treat MSW separately here otherwise the caret doesn't show
566// when the editor is in the first row.
a0948e27
MB
567#if defined(__WXMSW__)
568 int extra_y = 2;
569#else
cb105ad4 570 int extra_y = ( rect.y > 2 )? 2 : 1;
a0948e27
MB
571#endif // MSW
572
99306db2 573#if defined(__WXMOTIF__)
cb105ad4
SN
574 extra_x *= 2;
575 extra_y *= 2;
99306db2 576#endif
cb105ad4
SN
577 rect.SetLeft( wxMax(0, rect.x - extra_x) );
578 rect.SetTop( wxMax(0, rect.y - extra_y) );
579 rect.SetRight( rect.GetRight() + 2*extra_x );
580 rect.SetBottom( rect.GetBottom() + 2*extra_y );
99306db2
VZ
581#endif // GTK/!GTK
582
583 wxGridCellEditor::SetSize(rect);
584}
585
3da93aae 586void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
2796cce3
RD
587{
588 wxASSERT_MSG(m_control,
589 wxT("The wxGridCellEditor must be Created first!"));
590
591 m_startValue = grid->GetTable()->GetValue(row, col);
816be743
VZ
592
593 DoBeginEdit(m_startValue);
594}
595
596void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
597{
598 Text()->SetValue(startValue);
b54ba671
VZ
599 Text()->SetInsertionPointEnd();
600 Text()->SetFocus();
2796cce3
RD
601}
602
3324d5f5 603bool wxGridCellTextEditor::EndEdit(int row, int col,
3da93aae 604 wxGrid* grid)
2796cce3
RD
605{
606 wxASSERT_MSG(m_control,
607 wxT("The wxGridCellEditor must be Created first!"));
608
609 bool changed = FALSE;
b54ba671 610 wxString value = Text()->GetValue();
2796cce3
RD
611 if (value != m_startValue)
612 changed = TRUE;
613
614 if (changed)
615 grid->GetTable()->SetValue(row, col, value);
2c9a89e0 616
3da93aae 617 m_startValue = wxEmptyString;
b54ba671 618 Text()->SetValue(m_startValue);
2796cce3
RD
619
620 return changed;
621}
622
623
624void wxGridCellTextEditor::Reset()
625{
626 wxASSERT_MSG(m_control,
627 wxT("The wxGridCellEditor must be Created first!"));
628
816be743
VZ
629 DoReset(m_startValue);
630}
631
632void wxGridCellTextEditor::DoReset(const wxString& startValue)
633{
634 Text()->SetValue(startValue);
b54ba671 635 Text()->SetInsertionPointEnd();
2796cce3
RD
636}
637
f6bcfd97
BP
638bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
639{
640 if ( wxGridCellEditor::IsAcceptedKey(event) )
641 {
642 int keycode = event.GetKeyCode();
643 switch ( keycode )
644 {
645 case WXK_NUMPAD0:
646 case WXK_NUMPAD1:
647 case WXK_NUMPAD2:
648 case WXK_NUMPAD3:
649 case WXK_NUMPAD4:
650 case WXK_NUMPAD5:
651 case WXK_NUMPAD6:
652 case WXK_NUMPAD7:
653 case WXK_NUMPAD8:
654 case WXK_NUMPAD9:
655 case WXK_MULTIPLY:
656 case WXK_NUMPAD_MULTIPLY:
657 case WXK_ADD:
658 case WXK_NUMPAD_ADD:
659 case WXK_SUBTRACT:
660 case WXK_NUMPAD_SUBTRACT:
661 case WXK_DECIMAL:
662 case WXK_NUMPAD_DECIMAL:
663 case WXK_DIVIDE:
664 case WXK_NUMPAD_DIVIDE:
665 return TRUE;
666
667 default:
668 // accept 8 bit chars too if isprint() agrees
669 if ( (keycode < 255) && (isprint(keycode)) )
670 return TRUE;
671 }
672 }
673
674 return FALSE;
675}
676
2c9a89e0
RD
677void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
678{
f6bcfd97
BP
679 // we don't check for !HasModifiers() because IsAcceptedKey() did it
680
681 // insert the key in the control
682 wxChar ch;
683 int keycode = event.GetKeyCode();
684 switch ( keycode )
685 {
686 case WXK_NUMPAD0:
687 case WXK_NUMPAD1:
688 case WXK_NUMPAD2:
689 case WXK_NUMPAD3:
690 case WXK_NUMPAD4:
691 case WXK_NUMPAD5:
692 case WXK_NUMPAD6:
693 case WXK_NUMPAD7:
694 case WXK_NUMPAD8:
695 case WXK_NUMPAD9:
696 ch = _T('0') + keycode - WXK_NUMPAD0;
697 break;
b54ba671 698
f6bcfd97
BP
699 case WXK_MULTIPLY:
700 case WXK_NUMPAD_MULTIPLY:
701 ch = _T('*');
702 break;
b54ba671 703
f6bcfd97
BP
704 case WXK_ADD:
705 case WXK_NUMPAD_ADD:
706 ch = _T('+');
707 break;
2c9a89e0 708
f6bcfd97
BP
709 case WXK_SUBTRACT:
710 case WXK_NUMPAD_SUBTRACT:
711 ch = _T('-');
712 break;
713
714 case WXK_DECIMAL:
715 case WXK_NUMPAD_DECIMAL:
716 ch = _T('.');
717 break;
718
719 case WXK_DIVIDE:
720 case WXK_NUMPAD_DIVIDE:
721 ch = _T('/');
722 break;
723
724 default:
725 if ( keycode < 256 && keycode >= 0 && isprint(keycode) )
726 {
727 // FIXME this is not going to work for non letters...
728 if ( !event.ShiftDown() )
729 {
730 keycode = tolower(keycode);
731 }
732
733 ch = (wxChar)keycode;
734 }
735 else
736 {
737 ch = _T('\0');
738 }
2c9a89e0 739 }
2c9a89e0 740
f6bcfd97
BP
741 if ( ch )
742 {
743 Text()->AppendText(ch);
744 }
745 else
746 {
747 event.Skip();
748 }
b54ba671 749}
2c9a89e0 750
c78b3acd 751void wxGridCellTextEditor::HandleReturn( wxKeyEvent&
0b7e6e7d 752 WXUNUSED_GTK(WXUNUSED_MOTIF(event)) )
2796cce3
RD
753{
754#if defined(__WXMOTIF__) || defined(__WXGTK__)
755 // wxMotif needs a little extra help...
6fc0f38f 756 size_t pos = (size_t)( Text()->GetInsertionPoint() );
b54ba671 757 wxString s( Text()->GetValue() );
2796cce3 758 s = s.Left(pos) + "\n" + s.Mid(pos);
b54ba671
VZ
759 Text()->SetValue(s);
760 Text()->SetInsertionPoint( pos );
2796cce3
RD
761#else
762 // the other ports can handle a Return key press
763 //
764 event.Skip();
765#endif
766}
767
c4608a8a
VZ
768void wxGridCellTextEditor::SetParameters(const wxString& params)
769{
770 if ( !params )
771 {
772 // reset to default
773 m_maxChars = 0;
774 }
775 else
776 {
777 long tmp;
778 if ( !params.ToLong(&tmp) )
779 {
f6bcfd97 780 wxLogDebug(_T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str());
c4608a8a
VZ
781 }
782 else
783 {
784 m_maxChars = (size_t)tmp;
785 }
786 }
787}
788
816be743
VZ
789// ----------------------------------------------------------------------------
790// wxGridCellNumberEditor
791// ----------------------------------------------------------------------------
792
793wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
794{
795 m_min = min;
796 m_max = max;
797}
798
799void wxGridCellNumberEditor::Create(wxWindow* parent,
800 wxWindowID id,
801 wxEvtHandler* evtHandler)
802{
803 if ( HasRange() )
804 {
805 // create a spin ctrl
806 m_control = new wxSpinCtrl(parent, -1, wxEmptyString,
807 wxDefaultPosition, wxDefaultSize,
808 wxSP_ARROW_KEYS,
809 m_min, m_max);
810
811 wxGridCellEditor::Create(parent, id, evtHandler);
812 }
813 else
814 {
815 // just a text control
816 wxGridCellTextEditor::Create(parent, id, evtHandler);
817
818#if wxUSE_VALIDATORS
85bc0351 819 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
816be743
VZ
820#endif // wxUSE_VALIDATORS
821 }
822}
823
824void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
825{
826 // first get the value
827 wxGridTableBase *table = grid->GetTable();
828 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
829 {
830 m_valueOld = table->GetValueAsLong(row, col);
831 }
832 else
833 {
a5777624
RD
834 wxString sValue = table->GetValue(row, col);
835 if (! sValue.ToLong(&m_valueOld))
836 {
837 wxFAIL_MSG( _T("this cell doesn't have numeric value") );
838 return;
839 }
816be743
VZ
840 }
841
842 if ( HasRange() )
843 {
4a64bee4 844 Spin()->SetValue((int)m_valueOld);
f6bcfd97 845 Spin()->SetFocus();
816be743
VZ
846 }
847 else
848 {
849 DoBeginEdit(GetString());
850 }
851}
852
3324d5f5 853bool wxGridCellNumberEditor::EndEdit(int row, int col,
816be743
VZ
854 wxGrid* grid)
855{
856 bool changed;
857 long value;
858
859 if ( HasRange() )
860 {
861 value = Spin()->GetValue();
862 changed = value != m_valueOld;
863 }
864 else
865 {
866 changed = Text()->GetValue().ToLong(&value) && (value != m_valueOld);
867 }
868
869 if ( changed )
870 {
a5777624
RD
871 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
872 grid->GetTable()->SetValueAsLong(row, col, value);
873 else
f6bcfd97 874 grid->GetTable()->SetValue(row, col, wxString::Format(wxT("%ld"), value));
816be743
VZ
875 }
876
877 return changed;
878}
879
880void wxGridCellNumberEditor::Reset()
881{
882 if ( HasRange() )
883 {
4a64bee4 884 Spin()->SetValue((int)m_valueOld);
816be743
VZ
885 }
886 else
887 {
888 DoReset(GetString());
889 }
890}
891
f6bcfd97
BP
892bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event)
893{
894 if ( wxGridCellEditor::IsAcceptedKey(event) )
895 {
896 int keycode = event.GetKeyCode();
897 switch ( keycode )
898 {
899 case WXK_NUMPAD0:
900 case WXK_NUMPAD1:
901 case WXK_NUMPAD2:
902 case WXK_NUMPAD3:
903 case WXK_NUMPAD4:
904 case WXK_NUMPAD5:
905 case WXK_NUMPAD6:
906 case WXK_NUMPAD7:
907 case WXK_NUMPAD8:
908 case WXK_NUMPAD9:
909 case WXK_ADD:
910 case WXK_NUMPAD_ADD:
911 case WXK_SUBTRACT:
912 case WXK_NUMPAD_SUBTRACT:
913 case WXK_UP:
914 case WXK_DOWN:
915 return TRUE;
916
917 default:
918 if ( (keycode < 128) && isdigit(keycode) )
919 return TRUE;
920 }
921 }
922
923 return FALSE;
924}
925
816be743
VZ
926void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
927{
928 if ( !HasRange() )
929 {
4a64bee4 930 int keycode = (int) event.KeyCode();
816be743
VZ
931 if ( isdigit(keycode) || keycode == '+' || keycode == '-' )
932 {
933 wxGridCellTextEditor::StartingKey(event);
934
935 // skip Skip() below
936 return;
937 }
938 }
939
940 event.Skip();
941}
9c4ba614 942
c4608a8a
VZ
943void wxGridCellNumberEditor::SetParameters(const wxString& params)
944{
945 if ( !params )
946 {
947 // reset to default
948 m_min =
949 m_max = -1;
950 }
951 else
952 {
953 long tmp;
954 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
955 {
956 m_min = (int)tmp;
957
958 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
959 {
960 m_max = (int)tmp;
961
962 // skip the error message below
963 return;
964 }
965 }
966
f6bcfd97 967 wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
c4608a8a
VZ
968 }
969}
970
816be743
VZ
971// ----------------------------------------------------------------------------
972// wxGridCellFloatEditor
973// ----------------------------------------------------------------------------
974
f6bcfd97
BP
975wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision)
976{
977 m_width = width;
978 m_precision = precision;
979}
980
816be743
VZ
981void wxGridCellFloatEditor::Create(wxWindow* parent,
982 wxWindowID id,
983 wxEvtHandler* evtHandler)
984{
985 wxGridCellTextEditor::Create(parent, id, evtHandler);
986
987#if wxUSE_VALIDATORS
85bc0351 988 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
816be743
VZ
989#endif // wxUSE_VALIDATORS
990}
991
992void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
993{
994 // first get the value
995 wxGridTableBase *table = grid->GetTable();
996 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
997 {
998 m_valueOld = table->GetValueAsDouble(row, col);
999 }
1000 else
1001 {
a5777624
RD
1002 wxString sValue = table->GetValue(row, col);
1003 if (! sValue.ToDouble(&m_valueOld))
1004 {
1005 wxFAIL_MSG( _T("this cell doesn't have float value") );
1006 return;
1007 }
816be743
VZ
1008 }
1009
1010 DoBeginEdit(GetString());
1011}
1012
3324d5f5 1013bool wxGridCellFloatEditor::EndEdit(int row, int col,
816be743
VZ
1014 wxGrid* grid)
1015{
1016 double value;
1017 if ( Text()->GetValue().ToDouble(&value) && (value != m_valueOld) )
1018 {
a5777624
RD
1019 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
1020 grid->GetTable()->SetValueAsDouble(row, col, value);
1021 else
f6bcfd97 1022 grid->GetTable()->SetValue(row, col, wxString::Format(wxT("%f"), value));
816be743
VZ
1023
1024 return TRUE;
1025 }
1026 else
1027 {
1028 return FALSE;
1029 }
1030}
1031
1032void wxGridCellFloatEditor::Reset()
1033{
1034 DoReset(GetString());
1035}
1036
1037void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
1038{
4a64bee4 1039 int keycode = (int)event.KeyCode();
816be743
VZ
1040 if ( isdigit(keycode) ||
1041 keycode == '+' || keycode == '-' || keycode == '.' )
1042 {
1043 wxGridCellTextEditor::StartingKey(event);
1044
1045 // skip Skip() below
1046 return;
1047 }
1048
1049 event.Skip();
1050}
1051
f6bcfd97
BP
1052void wxGridCellFloatEditor::SetParameters(const wxString& params)
1053{
1054 if ( !params )
1055 {
1056 // reset to default
1057 m_width =
1058 m_precision = -1;
1059 }
1060 else
1061 {
1062 long tmp;
1063 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1064 {
1065 m_width = (int)tmp;
1066
1067 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1068 {
1069 m_precision = (int)tmp;
1070
1071 // skip the error message below
1072 return;
1073 }
1074 }
1075
1076 wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str());
1077 }
1078}
1079
1080wxString wxGridCellFloatEditor::GetString() const
1081{
1082 wxString fmt;
1083 if ( m_width == -1 )
1084 {
1085 // default width/precision
1086 fmt = _T("%g");
1087 }
1088 else if ( m_precision == -1 )
1089 {
1090 // default precision
1091 fmt.Printf(_T("%%%d.g"), m_width);
1092 }
1093 else
1094 {
1095 fmt.Printf(_T("%%%d.%dg"), m_width, m_precision);
1096 }
1097
1098 return wxString::Format(fmt, m_valueOld);
1099}
1100
1101bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
1102{
1103 if ( wxGridCellEditor::IsAcceptedKey(event) )
1104 {
1105 int keycode = event.GetKeyCode();
1106 switch ( keycode )
1107 {
1108 case WXK_NUMPAD0:
1109 case WXK_NUMPAD1:
1110 case WXK_NUMPAD2:
1111 case WXK_NUMPAD3:
1112 case WXK_NUMPAD4:
1113 case WXK_NUMPAD5:
1114 case WXK_NUMPAD6:
1115 case WXK_NUMPAD7:
1116 case WXK_NUMPAD8:
1117 case WXK_NUMPAD9:
1118 case WXK_ADD:
1119 case WXK_NUMPAD_ADD:
1120 case WXK_SUBTRACT:
1121 case WXK_NUMPAD_SUBTRACT:
1122 case WXK_DECIMAL:
1123 case WXK_NUMPAD_DECIMAL:
1124 return TRUE;
1125
1126 default:
1127 // additionally accept 'e' as in '1e+6'
1128 if ( (keycode < 128) &&
1129 (isdigit(keycode) || tolower(keycode) == 'e') )
1130 return TRUE;
1131 }
1132 }
1133
1134 return FALSE;
1135}
1136
508011ce
VZ
1137// ----------------------------------------------------------------------------
1138// wxGridCellBoolEditor
1139// ----------------------------------------------------------------------------
1140
1141void wxGridCellBoolEditor::Create(wxWindow* parent,
1142 wxWindowID id,
1143 wxEvtHandler* evtHandler)
1144{
1145 m_control = new wxCheckBox(parent, id, wxEmptyString,
1146 wxDefaultPosition, wxDefaultSize,
1147 wxNO_BORDER);
1148
1149 wxGridCellEditor::Create(parent, id, evtHandler);
1150}
1151
1152void wxGridCellBoolEditor::SetSize(const wxRect& r)
1153{
b94ae1ea
VZ
1154 bool resize = FALSE;
1155 wxSize size = m_control->GetSize();
1156 wxCoord minSize = wxMin(r.width, r.height);
1157
1158 // check if the checkbox is not too big/small for this cell
1159 wxSize sizeBest = m_control->GetBestSize();
1160 if ( !(size == sizeBest) )
1161 {
1162 // reset to default size if it had been made smaller
1163 size = sizeBest;
1164
1165 resize = TRUE;
1166 }
1167
1168 if ( size.x >= minSize || size.y >= minSize )
1169 {
1170 // leave 1 pixel margin
1171 size.x = size.y = minSize - 2;
1172
1173 resize = TRUE;
1174 }
1175
1176 if ( resize )
1177 {
1178 m_control->SetSize(size);
1179 }
1180
508011ce 1181 // position it in the centre of the rectangle (TODO: support alignment?)
508011ce 1182
b94ae1ea 1183#if defined(__WXGTK__) || defined (__WXMOTIF__)
508011ce
VZ
1184 // the checkbox without label still has some space to the right in wxGTK,
1185 // so shift it to the right
b94ae1ea
VZ
1186 size.x -= 8;
1187#elif defined(__WXMSW__)
a95e38c0
VZ
1188 // here too, but in other way
1189 size.x += 1;
b94ae1ea
VZ
1190 size.y -= 2;
1191#endif
508011ce 1192
b94ae1ea 1193 m_control->Move(r.x + r.width/2 - size.x/2, r.y + r.height/2 - size.y/2);
508011ce
VZ
1194}
1195
1196void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
1197{
99306db2
VZ
1198 m_control->Show(show);
1199
189d0213 1200 if ( show )
508011ce 1201 {
189d0213
VZ
1202 wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
1203 CBox()->SetBackgroundColour(colBg);
508011ce 1204 }
508011ce
VZ
1205}
1206
1207void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
1208{
1209 wxASSERT_MSG(m_control,
1210 wxT("The wxGridCellEditor must be Created first!"));
1211
28a77bc4 1212 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
f2d76237
RD
1213 m_startValue = grid->GetTable()->GetValueAsBool(row, col);
1214 else
695a3263
MB
1215 {
1216 wxString cellval( grid->GetTable()->GetValue(row, col) );
1217 m_startValue = !( !cellval || (cellval == "0") );
1218 }
508011ce
VZ
1219 CBox()->SetValue(m_startValue);
1220 CBox()->SetFocus();
1221}
1222
1223bool wxGridCellBoolEditor::EndEdit(int row, int col,
508011ce
VZ
1224 wxGrid* grid)
1225{
1226 wxASSERT_MSG(m_control,
1227 wxT("The wxGridCellEditor must be Created first!"));
1228
1229 bool changed = FALSE;
1230 bool value = CBox()->GetValue();
1231 if ( value != m_startValue )
1232 changed = TRUE;
1233
1234 if ( changed )
1235 {
28a77bc4 1236 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
f2d76237
RD
1237 grid->GetTable()->SetValueAsBool(row, col, value);
1238 else
1239 grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
508011ce
VZ
1240 }
1241
1242 return changed;
1243}
1244
1245void wxGridCellBoolEditor::Reset()
1246{
1247 wxASSERT_MSG(m_control,
1248 wxT("The wxGridCellEditor must be Created first!"));
1249
1250 CBox()->SetValue(m_startValue);
1251}
1252
e195a54c 1253void wxGridCellBoolEditor::StartingClick()
508011ce 1254{
e195a54c 1255 CBox()->SetValue(!CBox()->GetValue());
508011ce
VZ
1256}
1257
f6bcfd97
BP
1258bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event)
1259{
1260 if ( wxGridCellEditor::IsAcceptedKey(event) )
1261 {
1262 int keycode = event.GetKeyCode();
1263 switch ( keycode )
1264 {
1265 case WXK_MULTIPLY:
1266 case WXK_NUMPAD_MULTIPLY:
1267 case WXK_ADD:
1268 case WXK_NUMPAD_ADD:
1269 case WXK_SUBTRACT:
1270 case WXK_NUMPAD_SUBTRACT:
1271 case WXK_SPACE:
1272 case '+':
1273 case '-':
1274 return TRUE;
1275 }
1276 }
1277
1278 return FALSE;
1279}
1280
4ee5fc9c
VZ
1281// ----------------------------------------------------------------------------
1282// wxGridCellChoiceEditor
1283// ----------------------------------------------------------------------------
1284
1285wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
f6bcfd97 1286 const wxString choices[],
4ee5fc9c
VZ
1287 bool allowOthers)
1288 : m_allowOthers(allowOthers)
1289{
c4608a8a 1290 if ( count )
4ee5fc9c 1291 {
c4608a8a
VZ
1292 m_choices.Alloc(count);
1293 for ( size_t n = 0; n < count; n++ )
1294 {
1295 m_choices.Add(choices[n]);
1296 }
4ee5fc9c
VZ
1297 }
1298}
1299
c4608a8a
VZ
1300wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
1301{
1302 wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
1303 editor->m_allowOthers = m_allowOthers;
1304 editor->m_choices = m_choices;
1305
1306 return editor;
1307}
1308
4ee5fc9c
VZ
1309void wxGridCellChoiceEditor::Create(wxWindow* parent,
1310 wxWindowID id,
1311 wxEvtHandler* evtHandler)
1312{
1313 size_t count = m_choices.GetCount();
1314 wxString *choices = new wxString[count];
1315 for ( size_t n = 0; n < count; n++ )
1316 {
1317 choices[n] = m_choices[n];
1318 }
1319
1320 m_control = new wxComboBox(parent, id, wxEmptyString,
1321 wxDefaultPosition, wxDefaultSize,
1322 count, choices,
1323 m_allowOthers ? 0 : wxCB_READONLY);
1324
1325 delete [] choices;
1326
1327 wxGridCellEditor::Create(parent, id, evtHandler);
1328}
1329
a5777624
RD
1330void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
1331 wxGridCellAttr * attr)
4ee5fc9c
VZ
1332{
1333 // as we fill the entire client area, don't do anything here to minimize
1334 // flicker
a5777624
RD
1335
1336 // TODO: It doesn't actually fill the client area since the height of a
1337 // combo always defaults to the standard... Until someone has time to
1338 // figure out the right rectangle to paint, just do it the normal way...
1339 wxGridCellEditor::PaintBackground(rectCell, attr);
4ee5fc9c
VZ
1340}
1341
1342void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
1343{
1344 wxASSERT_MSG(m_control,
1345 wxT("The wxGridCellEditor must be Created first!"));
1346
1347 m_startValue = grid->GetTable()->GetValue(row, col);
1348
1349 Combo()->SetValue(m_startValue);
28a77bc4
RD
1350 size_t count = m_choices.GetCount();
1351 for (size_t i=0; i<count; i++)
1352 {
1353 if (m_startValue == m_choices[i])
1354 {
1355 Combo()->SetSelection(i);
1356 break;
1357 }
1358 }
4ee5fc9c
VZ
1359 Combo()->SetInsertionPointEnd();
1360 Combo()->SetFocus();
1361}
1362
28a77bc4 1363bool wxGridCellChoiceEditor::EndEdit(int row, int col,
4ee5fc9c
VZ
1364 wxGrid* grid)
1365{
1366 wxString value = Combo()->GetValue();
1367 bool changed = value != m_startValue;
1368
1369 if ( changed )
1370 grid->GetTable()->SetValue(row, col, value);
1371
1372 m_startValue = wxEmptyString;
1373 Combo()->SetValue(m_startValue);
1374
1375 return changed;
1376}
1377
1378void wxGridCellChoiceEditor::Reset()
1379{
1380 Combo()->SetValue(m_startValue);
1381 Combo()->SetInsertionPointEnd();
1382}
1383
c4608a8a
VZ
1384void wxGridCellChoiceEditor::SetParameters(const wxString& params)
1385{
1386 if ( !params )
1387 {
1388 // what can we do?
1389 return;
1390 }
1391
1392 m_choices.Empty();
1393
1394 wxStringTokenizer tk(params, _T(','));
1395 while ( tk.HasMoreTokens() )
1396 {
1397 m_choices.Add(tk.GetNextToken());
1398 }
1399}
1400
508011ce
VZ
1401// ----------------------------------------------------------------------------
1402// wxGridCellEditorEvtHandler
1403// ----------------------------------------------------------------------------
2796cce3
RD
1404
1405void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
1406{
1407 switch ( event.KeyCode() )
1408 {
1409 case WXK_ESCAPE:
1410 m_editor->Reset();
b54ba671 1411 m_grid->DisableCellEditControl();
2796cce3
RD
1412 break;
1413
2c9a89e0 1414 case WXK_TAB:
ffdd3c98 1415 event.Skip( m_grid->GetEventHandler()->ProcessEvent( event ) );
9b4aede2
RD
1416 break;
1417
2796cce3 1418 case WXK_RETURN:
faec5a43
SN
1419 case WXK_NUMPAD_ENTER:
1420 if (!m_grid->GetEventHandler()->ProcessEvent(event))
2796cce3
RD
1421 m_editor->HandleReturn(event);
1422 break;
1423
2796cce3
RD
1424
1425 default:
1426 event.Skip();
1427 }
1428}
1429
fb0de762
RD
1430void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
1431{
1432 switch ( event.KeyCode() )
1433 {
1434 case WXK_ESCAPE:
1435 case WXK_TAB:
1436 case WXK_RETURN:
a4f7bf58 1437 case WXK_NUMPAD_ENTER:
fb0de762
RD
1438 break;
1439
1440 default:
1441 event.Skip();
1442 }
1443}
1444
c4608a8a
VZ
1445// ----------------------------------------------------------------------------
1446// wxGridCellWorker is an (almost) empty common base class for
1447// wxGridCellRenderer and wxGridCellEditor managing ref counting
1448// ----------------------------------------------------------------------------
1449
1450void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params))
1451{
1452 // nothing to do
1453}
1454
1455wxGridCellWorker::~wxGridCellWorker()
1456{
1457}
1458
508011ce
VZ
1459// ============================================================================
1460// renderer classes
1461// ============================================================================
1462
ab79958a
VZ
1463// ----------------------------------------------------------------------------
1464// wxGridCellRenderer
1465// ----------------------------------------------------------------------------
1466
1467void wxGridCellRenderer::Draw(wxGrid& grid,
2796cce3 1468 wxGridCellAttr& attr,
ab79958a
VZ
1469 wxDC& dc,
1470 const wxRect& rect,
c78b3acd 1471 int WXUNUSED(row), int WXUNUSED(col),
ab79958a
VZ
1472 bool isSelected)
1473{
1474 dc.SetBackgroundMode( wxSOLID );
1475
1476 if ( isSelected )
1477 {
2796cce3 1478 dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
ab79958a
VZ
1479 }
1480 else
1481 {
2796cce3 1482 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
ab79958a
VZ
1483 }
1484
1485 dc.SetPen( *wxTRANSPARENT_PEN );
ab79958a
VZ
1486 dc.DrawRectangle(rect);
1487}
1488
508011ce
VZ
1489// ----------------------------------------------------------------------------
1490// wxGridCellStringRenderer
1491// ----------------------------------------------------------------------------
1492
816be743
VZ
1493void wxGridCellStringRenderer::SetTextColoursAndFont(wxGrid& grid,
1494 wxGridCellAttr& attr,
1495 wxDC& dc,
1496 bool isSelected)
ab79958a 1497{
ab79958a
VZ
1498 dc.SetBackgroundMode( wxTRANSPARENT );
1499
283b7808
VZ
1500 // TODO some special colours for attr.IsReadOnly() case?
1501
ab79958a
VZ
1502 if ( isSelected )
1503 {
2796cce3
RD
1504 dc.SetTextBackground( grid.GetSelectionBackground() );
1505 dc.SetTextForeground( grid.GetSelectionForeground() );
ab79958a
VZ
1506 }
1507 else
1508 {
2796cce3
RD
1509 dc.SetTextBackground( attr.GetBackgroundColour() );
1510 dc.SetTextForeground( attr.GetTextColour() );
ab79958a 1511 }
816be743 1512
2796cce3 1513 dc.SetFont( attr.GetFont() );
816be743
VZ
1514}
1515
65e4e78e
VZ
1516wxSize wxGridCellStringRenderer::DoGetBestSize(wxGridCellAttr& attr,
1517 wxDC& dc,
1518 const wxString& text)
1519{
f6bcfd97 1520 wxCoord x = 0, y = 0, max_x = 0;
65e4e78e 1521 dc.SetFont(attr.GetFont());
f6bcfd97
BP
1522 wxStringTokenizer tk(text, _T('\n'));
1523 while ( tk.HasMoreTokens() )
1524 {
1525 dc.GetTextExtent(tk.GetNextToken(), &x, &y);
1526 max_x = wxMax(max_x, x);
1527 }
1528
1529 y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
65e4e78e 1530
f6bcfd97 1531 return wxSize(max_x, y);
65e4e78e
VZ
1532}
1533
1534wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
1535 wxGridCellAttr& attr,
1536 wxDC& dc,
1537 int row, int col)
1538{
1539 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
1540}
1541
816be743
VZ
1542void wxGridCellStringRenderer::Draw(wxGrid& grid,
1543 wxGridCellAttr& attr,
1544 wxDC& dc,
1545 const wxRect& rectCell,
1546 int row, int col,
1547 bool isSelected)
1548{
1549 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1550
1551 // now we only have to draw the text
1552 SetTextColoursAndFont(grid, attr, dc, isSelected);
ab79958a
VZ
1553
1554 int hAlign, vAlign;
2796cce3 1555 attr.GetAlignment(&hAlign, &vAlign);
ab79958a
VZ
1556
1557 wxRect rect = rectCell;
816be743 1558 rect.Inflate(-1);
ab79958a
VZ
1559
1560 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
1561 rect, hAlign, vAlign);
1562}
1563
65e4e78e
VZ
1564// ----------------------------------------------------------------------------
1565// wxGridCellNumberRenderer
1566// ----------------------------------------------------------------------------
1567
1568wxString wxGridCellNumberRenderer::GetString(wxGrid& grid, int row, int col)
1569{
1570 wxGridTableBase *table = grid.GetTable();
1571 wxString text;
1572 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
1573 {
1574 text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
1575 }
9c4ba614
VZ
1576 else
1577 {
1578 text = table->GetValue(row, col);
1579 }
65e4e78e
VZ
1580
1581 return text;
1582}
1583
816be743
VZ
1584void wxGridCellNumberRenderer::Draw(wxGrid& grid,
1585 wxGridCellAttr& attr,
1586 wxDC& dc,
1587 const wxRect& rectCell,
1588 int row, int col,
1589 bool isSelected)
1590{
1591 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1592
1593 SetTextColoursAndFont(grid, attr, dc, isSelected);
1594
1595 // draw the text right aligned by default
1596 int hAlign, vAlign;
1597 attr.GetAlignment(&hAlign, &vAlign);
4c7277db 1598 hAlign = wxALIGN_RIGHT;
816be743
VZ
1599
1600 wxRect rect = rectCell;
1601 rect.Inflate(-1);
1602
65e4e78e
VZ
1603 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1604}
816be743 1605
65e4e78e
VZ
1606wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
1607 wxGridCellAttr& attr,
1608 wxDC& dc,
1609 int row, int col)
1610{
1611 return DoGetBestSize(attr, dc, GetString(grid, row, col));
816be743
VZ
1612}
1613
1614// ----------------------------------------------------------------------------
1615// wxGridCellFloatRenderer
1616// ----------------------------------------------------------------------------
1617
1618wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
1619{
1620 SetWidth(width);
1621 SetPrecision(precision);
1622}
1623
e72b4213
VZ
1624wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
1625{
1626 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
1627 renderer->m_width = m_width;
1628 renderer->m_precision = m_precision;
1629 renderer->m_format = m_format;
1630
1631 return renderer;
1632}
1633
65e4e78e
VZ
1634wxString wxGridCellFloatRenderer::GetString(wxGrid& grid, int row, int col)
1635{
1636 wxGridTableBase *table = grid.GetTable();
0b190b0f
VZ
1637
1638 bool hasDouble;
1639 double val;
65e4e78e
VZ
1640 wxString text;
1641 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1642 {
0b190b0f
VZ
1643 val = table->GetValueAsDouble(row, col);
1644 hasDouble = TRUE;
65e4e78e 1645 }
9c4ba614
VZ
1646 else
1647 {
1648 text = table->GetValue(row, col);
0b190b0f 1649 hasDouble = text.ToDouble(&val);
9c4ba614 1650 }
65e4e78e 1651
0b190b0f
VZ
1652 if ( hasDouble )
1653 {
1654 if ( !m_format )
1655 {
1656 if ( m_width == -1 )
1657 {
1658 // default width/precision
1659 m_format = _T("%f");
1660 }
1661 else if ( m_precision == -1 )
1662 {
1663 // default precision
1664 m_format.Printf(_T("%%%d.f"), m_width);
1665 }
1666 else
1667 {
1668 m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
1669 }
1670 }
1671
1672 text.Printf(m_format, val);
1673 }
1674 //else: text already contains the string
1675
65e4e78e
VZ
1676 return text;
1677}
1678
816be743
VZ
1679void wxGridCellFloatRenderer::Draw(wxGrid& grid,
1680 wxGridCellAttr& attr,
1681 wxDC& dc,
1682 const wxRect& rectCell,
1683 int row, int col,
1684 bool isSelected)
1685{
1686 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1687
1688 SetTextColoursAndFont(grid, attr, dc, isSelected);
1689
1690 // draw the text right aligned by default
1691 int hAlign, vAlign;
1692 attr.GetAlignment(&hAlign, &vAlign);
4c7277db 1693 hAlign = wxALIGN_RIGHT;
816be743
VZ
1694
1695 wxRect rect = rectCell;
1696 rect.Inflate(-1);
1697
65e4e78e
VZ
1698 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1699}
816be743 1700
65e4e78e
VZ
1701wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
1702 wxGridCellAttr& attr,
1703 wxDC& dc,
1704 int row, int col)
1705{
1706 return DoGetBestSize(attr, dc, GetString(grid, row, col));
816be743
VZ
1707}
1708
0b190b0f
VZ
1709void wxGridCellFloatRenderer::SetParameters(const wxString& params)
1710{
1711 bool ok = TRUE;
1712
1713 if ( !params )
1714 {
1715 // reset to defaults
1716 SetWidth(-1);
1717 SetPrecision(-1);
1718 }
1719 else
1720 {
1721 wxString tmp = params.BeforeFirst(_T(','));
1722 if ( !!tmp )
1723 {
1724 long width;
1725 if ( !tmp.ToLong(&width) )
1726 {
1727 ok = FALSE;
1728 }
1729 else
1730 {
1731 SetWidth((int)width);
1732
1733 tmp = params.AfterFirst(_T(','));
1734 if ( !!tmp )
1735 {
1736 long precision;
1737 if ( !tmp.ToLong(&precision) )
1738 {
1739 ok = FALSE;
1740 }
1741 else
1742 {
1743 SetPrecision((int)precision);
1744 }
1745 }
1746 }
1747 }
1748
1749 if ( !ok )
1750 {
f6bcfd97 1751 wxLogDebug(_T("Invalid wxGridCellFloatRenderer parameter string '%s ignored"), params.c_str());
0b190b0f
VZ
1752 }
1753 }
1754}
1755
508011ce
VZ
1756// ----------------------------------------------------------------------------
1757// wxGridCellBoolRenderer
1758// ----------------------------------------------------------------------------
1759
65e4e78e 1760wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
508011ce 1761
b94ae1ea
VZ
1762// FIXME these checkbox size calculations are really ugly...
1763
65e4e78e 1764// between checkmark and box
a95e38c0 1765static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
508011ce 1766
65e4e78e
VZ
1767wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
1768 wxGridCellAttr& WXUNUSED(attr),
1769 wxDC& WXUNUSED(dc),
1770 int WXUNUSED(row),
1771 int WXUNUSED(col))
1772{
1773 // compute it only once (no locks for MT safeness in GUI thread...)
1774 if ( !ms_sizeCheckMark.x )
297da4ba 1775 {
65e4e78e
VZ
1776 // get checkbox size
1777 wxCoord checkSize = 0;
297da4ba
VZ
1778 wxCheckBox *checkbox = new wxCheckBox(&grid, -1, wxEmptyString);
1779 wxSize size = checkbox->GetBestSize();
a95e38c0 1780 checkSize = size.y + 2*wxGRID_CHECKMARK_MARGIN;
297da4ba 1781
65e4e78e 1782 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
69d8f612 1783#if defined(__WXGTK__) || defined(__WXMOTIF__)
65e4e78e 1784 checkSize -= size.y / 2;
297da4ba
VZ
1785#endif
1786
1787 delete checkbox;
65e4e78e
VZ
1788
1789 ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
297da4ba
VZ
1790 }
1791
65e4e78e
VZ
1792 return ms_sizeCheckMark;
1793}
1794
1795void wxGridCellBoolRenderer::Draw(wxGrid& grid,
1796 wxGridCellAttr& attr,
1797 wxDC& dc,
1798 const wxRect& rect,
1799 int row, int col,
1800 bool isSelected)
1801{
1802 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
1803
297da4ba 1804 // draw a check mark in the centre (ignoring alignment - TODO)
65e4e78e 1805 wxSize size = GetBestSize(grid, attr, dc, row, col);
b94ae1ea
VZ
1806
1807 // don't draw outside the cell
1808 wxCoord minSize = wxMin(rect.width, rect.height);
1809 if ( size.x >= minSize || size.y >= minSize )
1810 {
1811 // and even leave (at least) 1 pixel margin
1812 size.x = size.y = minSize - 2;
1813 }
1814
1815 // draw a border around checkmark
a95e38c0
VZ
1816 wxRect rectBorder;
1817 rectBorder.x = rect.x + rect.width/2 - size.x/2;
1818 rectBorder.y = rect.y + rect.height/2 - size.y/2;
1819 rectBorder.width = size.x;
1820 rectBorder.height = size.y;
b94ae1ea 1821
f2d76237 1822 bool value;
b94ae1ea 1823 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
f2d76237
RD
1824 value = grid.GetTable()->GetValueAsBool(row, col);
1825 else
695a3263
MB
1826 {
1827 wxString cellval( grid.GetTable()->GetValue(row, col) );
1828 value = !( !cellval || (cellval == "0") );
1829 }
f2d76237
RD
1830
1831 if ( value )
508011ce 1832 {
a95e38c0
VZ
1833 wxRect rectMark = rectBorder;
1834#ifdef __WXMSW__
1835 // MSW DrawCheckMark() is weird (and should probably be changed...)
1836 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN/2);
1837 rectMark.x++;
1838 rectMark.y++;
1839#else // !MSW
1840 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
1841#endif // MSW/!MSW
1842
508011ce
VZ
1843 dc.SetTextForeground(attr.GetTextColour());
1844 dc.DrawCheckMark(rectMark);
1845 }
a95e38c0
VZ
1846
1847 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1848 dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
1849 dc.DrawRectangle(rectBorder);
508011ce
VZ
1850}
1851
2796cce3
RD
1852// ----------------------------------------------------------------------------
1853// wxGridCellAttr
1854// ----------------------------------------------------------------------------
1855
39bcce60 1856wxGridCellAttr *wxGridCellAttr::Clone() const
a68c1246
VZ
1857{
1858 wxGridCellAttr *attr = new wxGridCellAttr;
1859 if ( HasTextColour() )
1860 attr->SetTextColour(GetTextColour());
1861 if ( HasBackgroundColour() )
1862 attr->SetBackgroundColour(GetBackgroundColour());
1863 if ( HasFont() )
1864 attr->SetFont(GetFont());
1865 if ( HasAlignment() )
1866 attr->SetAlignment(m_hAlign, m_vAlign);
1867
1868 if ( m_renderer )
1869 {
1870 attr->SetRenderer(m_renderer);
39bcce60 1871 m_renderer->IncRef();
a68c1246
VZ
1872 }
1873 if ( m_editor )
1874 {
1875 attr->SetEditor(m_editor);
39bcce60 1876 m_editor->IncRef();
a68c1246
VZ
1877 }
1878
1879 if ( IsReadOnly() )
1880 attr->SetReadOnly();
1881
1882 attr->SetDefAttr(m_defGridAttr);
1883
1884 return attr;
1885}
1886
2796cce3
RD
1887const wxColour& wxGridCellAttr::GetTextColour() const
1888{
1889 if (HasTextColour())
508011ce 1890 {
2796cce3 1891 return m_colText;
508011ce 1892 }
2796cce3 1893 else if (m_defGridAttr != this)
508011ce 1894 {
2796cce3 1895 return m_defGridAttr->GetTextColour();
508011ce
VZ
1896 }
1897 else
1898 {
2796cce3
RD
1899 wxFAIL_MSG(wxT("Missing default cell attribute"));
1900 return wxNullColour;
1901 }
1902}
1903
1904
1905const wxColour& wxGridCellAttr::GetBackgroundColour() const
1906{
1907 if (HasBackgroundColour())
1908 return m_colBack;
1909 else if (m_defGridAttr != this)
1910 return m_defGridAttr->GetBackgroundColour();
508011ce
VZ
1911 else
1912 {
2796cce3
RD
1913 wxFAIL_MSG(wxT("Missing default cell attribute"));
1914 return wxNullColour;
1915 }
1916}
1917
1918
1919const wxFont& wxGridCellAttr::GetFont() const
1920{
1921 if (HasFont())
1922 return m_font;
1923 else if (m_defGridAttr != this)
1924 return m_defGridAttr->GetFont();
508011ce
VZ
1925 else
1926 {
2796cce3
RD
1927 wxFAIL_MSG(wxT("Missing default cell attribute"));
1928 return wxNullFont;
1929 }
1930}
1931
1932
1933void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
1934{
508011ce
VZ
1935 if (HasAlignment())
1936 {
2796cce3
RD
1937 if ( hAlign ) *hAlign = m_hAlign;
1938 if ( vAlign ) *vAlign = m_vAlign;
1939 }
1940 else if (m_defGridAttr != this)
1941 m_defGridAttr->GetAlignment(hAlign, vAlign);
508011ce
VZ
1942 else
1943 {
2796cce3
RD
1944 wxFAIL_MSG(wxT("Missing default cell attribute"));
1945 }
1946}
1947
1948
f2d76237 1949// GetRenderer and GetEditor use a slightly different decision path about
28a77bc4
RD
1950// which attribute to use. If a non-default attr object has one then it is
1951// used, otherwise the default editor or renderer is fetched from the grid and
1952// used. It should be the default for the data type of the cell. If it is
1953// NULL (because the table has a type that the grid does not have in its
1954// registry,) then the grid's default editor or renderer is used.
1955
1956wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
1957{
28a77bc4 1958 wxGridCellRenderer* renderer = NULL;
28a77bc4 1959
0b190b0f
VZ
1960 if ( m_defGridAttr != this || grid == NULL )
1961 {
1962 renderer = m_renderer; // use local attribute
1963 if ( renderer )
1964 renderer->IncRef();
1965 }
1966
1967 if ( !renderer && grid ) // get renderer for the data type
1968 {
1969 // GetDefaultRendererForCell() will do IncRef() for us
1970 renderer = grid->GetDefaultRendererForCell(row, col);
1971 }
1972
1973 if ( !renderer )
1974 {
28a77bc4 1975 // if we still don't have one then use the grid default
0b190b0f 1976 // (no need for IncRef() here neither)
28a77bc4 1977 renderer = m_defGridAttr->GetRenderer(NULL,0,0);
0b190b0f 1978 }
28a77bc4 1979
0b190b0f
VZ
1980 if ( !renderer)
1981 {
2796cce3 1982 wxFAIL_MSG(wxT("Missing default cell attribute"));
0b190b0f 1983 }
28a77bc4
RD
1984
1985 return renderer;
2796cce3
RD
1986}
1987
28a77bc4 1988wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
07296f0b 1989{
28a77bc4 1990 wxGridCellEditor* editor = NULL;
0b190b0f
VZ
1991
1992 if ( m_defGridAttr != this || grid == NULL )
1993 {
1994 editor = m_editor; // use local attribute
1995 if ( editor )
1996 editor->IncRef();
1997 }
1998
a95e38c0
VZ
1999 if ( !editor && grid ) // get renderer for the data type
2000 editor = grid->GetDefaultEditorForCell(row, col);
28a77bc4 2001
0b190b0f 2002 if ( !editor )
28a77bc4
RD
2003 // if we still don't have one then use the grid default
2004 editor = m_defGridAttr->GetEditor(NULL,0,0);
2005
0b190b0f
VZ
2006 if ( !editor )
2007 {
07296f0b 2008 wxFAIL_MSG(wxT("Missing default cell attribute"));
0b190b0f 2009 }
28a77bc4
RD
2010
2011 return editor;
07296f0b
RD
2012}
2013
b99be8fb 2014// ----------------------------------------------------------------------------
758cbedf 2015// wxGridCellAttrData
b99be8fb
VZ
2016// ----------------------------------------------------------------------------
2017
758cbedf 2018void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
b99be8fb
VZ
2019{
2020 int n = FindIndex(row, col);
2021 if ( n == wxNOT_FOUND )
2022 {
2023 // add the attribute
2024 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
2025 }
2026 else
2027 {
2028 if ( attr )
2029 {
2030 // change the attribute
2e9a6788 2031 m_attrs[(size_t)n].attr = attr;
b99be8fb
VZ
2032 }
2033 else
2034 {
2035 // remove this attribute
2036 m_attrs.RemoveAt((size_t)n);
2037 }
2038 }
b99be8fb
VZ
2039}
2040
758cbedf 2041wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
b99be8fb
VZ
2042{
2043 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2044
2045 int n = FindIndex(row, col);
2046 if ( n != wxNOT_FOUND )
2047 {
2e9a6788
VZ
2048 attr = m_attrs[(size_t)n].attr;
2049 attr->IncRef();
b99be8fb
VZ
2050 }
2051
2052 return attr;
2053}
2054
4d60017a
SN
2055void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
2056{
2057 size_t count = m_attrs.GetCount();
2058 for ( size_t n = 0; n < count; n++ )
2059 {
2060 wxGridCellCoords& coords = m_attrs[n].coords;
d1c0b4f9
VZ
2061 wxCoord row = coords.GetRow();
2062 if ((size_t)row >= pos)
2063 {
2064 if (numRows > 0)
2065 {
2066 // If rows inserted, include row counter where necessary
2067 coords.SetRow(row + numRows);
2068 }
2069 else if (numRows < 0)
2070 {
2071 // If rows deleted ...
2072 if ((size_t)row >= pos - numRows)
2073 {
2074 // ...either decrement row counter (if row still exists)...
2075 coords.SetRow(row + numRows);
2076 }
2077 else
2078 {
2079 // ...or remove the attribute
2080 m_attrs.RemoveAt((size_t)n);
2081 n--; count--;
2082 }
2083 }
4d60017a
SN
2084 }
2085 }
2086}
2087
2088void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
2089{
2090 size_t count = m_attrs.GetCount();
2091 for ( size_t n = 0; n < count; n++ )
2092 {
2093 wxGridCellCoords& coords = m_attrs[n].coords;
d1c0b4f9
VZ
2094 wxCoord col = coords.GetCol();
2095 if ( (size_t)col >= pos )
2096 {
2097 if ( numCols > 0 )
2098 {
2099 // If rows inserted, include row counter where necessary
2100 coords.SetCol(col + numCols);
2101 }
2102 else if (numCols < 0)
2103 {
2104 // If rows deleted ...
2105 if ((size_t)col >= pos - numCols)
2106 {
2107 // ...either decrement row counter (if row still exists)...
2108 coords.SetCol(col + numCols);
2109 }
2110 else
2111 {
2112 // ...or remove the attribute
2113 m_attrs.RemoveAt((size_t)n);
2114 n--; count--;
2115 }
2116 }
4d60017a
SN
2117 }
2118 }
2119}
2120
758cbedf 2121int wxGridCellAttrData::FindIndex(int row, int col) const
b99be8fb
VZ
2122{
2123 size_t count = m_attrs.GetCount();
2124 for ( size_t n = 0; n < count; n++ )
2125 {
2126 const wxGridCellCoords& coords = m_attrs[n].coords;
2127 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
2128 {
2129 return n;
2130 }
2131 }
2132
2133 return wxNOT_FOUND;
2134}
2135
758cbedf
VZ
2136// ----------------------------------------------------------------------------
2137// wxGridRowOrColAttrData
2138// ----------------------------------------------------------------------------
2139
2140wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
2141{
2142 size_t count = m_attrs.Count();
2143 for ( size_t n = 0; n < count; n++ )
2144 {
2145 m_attrs[n]->DecRef();
2146 }
2147}
2148
2149wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
2150{
2151 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2152
2153 int n = m_rowsOrCols.Index(rowOrCol);
2154 if ( n != wxNOT_FOUND )
2155 {
2156 attr = m_attrs[(size_t)n];
2157 attr->IncRef();
2158 }
2159
2160 return attr;
2161}
2162
2163void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
2164{
a95e38c0
VZ
2165 int i = m_rowsOrCols.Index(rowOrCol);
2166 if ( i == wxNOT_FOUND )
758cbedf
VZ
2167 {
2168 // add the attribute
2169 m_rowsOrCols.Add(rowOrCol);
2170 m_attrs.Add(attr);
2171 }
2172 else
2173 {
a95e38c0 2174 size_t n = (size_t)i;
758cbedf
VZ
2175 if ( attr )
2176 {
2177 // change the attribute
a95e38c0
VZ
2178 m_attrs[n]->DecRef();
2179 m_attrs[n] = attr;
758cbedf
VZ
2180 }
2181 else
2182 {
2183 // remove this attribute
a95e38c0
VZ
2184 m_attrs[n]->DecRef();
2185 m_rowsOrCols.RemoveAt(n);
2186 m_attrs.RemoveAt(n);
758cbedf
VZ
2187 }
2188 }
2189}
2190
4d60017a
SN
2191void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
2192{
2193 size_t count = m_attrs.GetCount();
2194 for ( size_t n = 0; n < count; n++ )
2195 {
2196 int & rowOrCol = m_rowsOrCols[n];
d1c0b4f9
VZ
2197 if ( (size_t)rowOrCol >= pos )
2198 {
2199 if ( numRowsOrCols > 0 )
2200 {
2201 // If rows inserted, include row counter where necessary
2202 rowOrCol += numRowsOrCols;
2203 }
2204 else if ( numRowsOrCols < 0)
2205 {
2206 // If rows deleted, either decrement row counter (if row still exists)
2207 if ((size_t)rowOrCol >= pos - numRowsOrCols)
2208 rowOrCol += numRowsOrCols;
2209 else
2210 {
2211 m_rowsOrCols.RemoveAt((size_t)n);
2212 m_attrs.RemoveAt((size_t)n);
2213 n--; count--;
2214 }
2215 }
4d60017a
SN
2216 }
2217 }
2218}
2219
b99be8fb
VZ
2220// ----------------------------------------------------------------------------
2221// wxGridCellAttrProvider
2222// ----------------------------------------------------------------------------
2223
2224wxGridCellAttrProvider::wxGridCellAttrProvider()
2225{
2226 m_data = (wxGridCellAttrProviderData *)NULL;
2227}
2228
2229wxGridCellAttrProvider::~wxGridCellAttrProvider()
2230{
2231 delete m_data;
2232}
2233
2234void wxGridCellAttrProvider::InitData()
2235{
2236 m_data = new wxGridCellAttrProviderData;
2237}
2238
2239wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col) const
2240{
758cbedf
VZ
2241 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2242 if ( m_data )
2243 {
2244 // first look for the attribute of this specific cell
2245 attr = m_data->m_cellAttrs.GetAttr(row, col);
2246
2247 if ( !attr )
2248 {
2249 // then look for the col attr (col attributes are more common than
2250 // the row ones, hence they have priority)
2251 attr = m_data->m_colAttrs.GetAttr(col);
2252 }
2253
2254 if ( !attr )
2255 {
2256 // finally try the row attributes
2257 attr = m_data->m_rowAttrs.GetAttr(row);
2258 }
2259 }
2260
2261 return attr;
b99be8fb
VZ
2262}
2263
2e9a6788 2264void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
b99be8fb
VZ
2265 int row, int col)
2266{
2267 if ( !m_data )
2268 InitData();
2269
758cbedf
VZ
2270 m_data->m_cellAttrs.SetAttr(attr, row, col);
2271}
2272
2273void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
2274{
2275 if ( !m_data )
2276 InitData();
2277
2278 m_data->m_rowAttrs.SetAttr(attr, row);
2279}
2280
2281void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
2282{
2283 if ( !m_data )
2284 InitData();
2285
2286 m_data->m_colAttrs.SetAttr(attr, col);
b99be8fb
VZ
2287}
2288
4d60017a
SN
2289void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
2290{
2291 if ( m_data )
2292 {
2293 m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
2294
d1c0b4f9 2295 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
4d60017a
SN
2296 }
2297}
2298
2299void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
2300{
2301 if ( m_data )
2302 {
2303 m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
2304
d1c0b4f9 2305 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
4d60017a
SN
2306 }
2307}
2308
f2d76237
RD
2309// ----------------------------------------------------------------------------
2310// wxGridTypeRegistry
2311// ----------------------------------------------------------------------------
2312
2313wxGridTypeRegistry::~wxGridTypeRegistry()
2314{
b94ae1ea
VZ
2315 size_t count = m_typeinfo.Count();
2316 for ( size_t i = 0; i < count; i++ )
f2d76237
RD
2317 delete m_typeinfo[i];
2318}
2319
2320
2321void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
2322 wxGridCellRenderer* renderer,
2323 wxGridCellEditor* editor)
2324{
f2d76237
RD
2325 wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
2326
2327 // is it already registered?
c4608a8a 2328 int loc = FindRegisteredDataType(typeName);
39bcce60
VZ
2329 if ( loc != wxNOT_FOUND )
2330 {
f2d76237
RD
2331 delete m_typeinfo[loc];
2332 m_typeinfo[loc] = info;
2333 }
39bcce60
VZ
2334 else
2335 {
f2d76237
RD
2336 m_typeinfo.Add(info);
2337 }
2338}
2339
c4608a8a
VZ
2340int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
2341{
2342 size_t count = m_typeinfo.GetCount();
2343 for ( size_t i = 0; i < count; i++ )
2344 {
2345 if ( typeName == m_typeinfo[i]->m_typeName )
2346 {
2347 return i;
2348 }
2349 }
2350
2351 return wxNOT_FOUND;
2352}
2353
f2d76237
RD
2354int wxGridTypeRegistry::FindDataType(const wxString& typeName)
2355{
c4608a8a
VZ
2356 int index = FindRegisteredDataType(typeName);
2357 if ( index == wxNOT_FOUND )
2358 {
2359 // check whether this is one of the standard ones, in which case
2360 // register it "on the fly"
2361 if ( typeName == wxGRID_VALUE_STRING )
2362 {
2363 RegisterDataType(wxGRID_VALUE_STRING,
2364 new wxGridCellStringRenderer,
2365 new wxGridCellTextEditor);
2366 }
2367 else if ( typeName == wxGRID_VALUE_BOOL )
2368 {
2369 RegisterDataType(wxGRID_VALUE_BOOL,
2370 new wxGridCellBoolRenderer,
2371 new wxGridCellBoolEditor);
2372 }
2373 else if ( typeName == wxGRID_VALUE_NUMBER )
2374 {
2375 RegisterDataType(wxGRID_VALUE_NUMBER,
2376 new wxGridCellNumberRenderer,
2377 new wxGridCellNumberEditor);
2378 }
2379 else if ( typeName == wxGRID_VALUE_FLOAT )
2380 {
2381 RegisterDataType(wxGRID_VALUE_FLOAT,
2382 new wxGridCellFloatRenderer,
2383 new wxGridCellFloatEditor);
2384 }
2385 else if ( typeName == wxGRID_VALUE_CHOICE )
2386 {
2387 RegisterDataType(wxGRID_VALUE_CHOICE,
2388 new wxGridCellStringRenderer,
2389 new wxGridCellChoiceEditor);
2390 }
2391 else
2392 {
2393 return wxNOT_FOUND;
2394 }
f2d76237 2395
c4608a8a
VZ
2396 // we get here only if just added the entry for this type, so return
2397 // the last index
2398 index = m_typeinfo.GetCount() - 1;
2399 }
2400
2401 return index;
2402}
2403
2404int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
2405{
2406 int index = FindDataType(typeName);
2407 if ( index == wxNOT_FOUND )
2408 {
2409 // the first part of the typename is the "real" type, anything after ':'
2410 // are the parameters for the renderer
2411 index = FindDataType(typeName.BeforeFirst(_T(':')));
2412 if ( index == wxNOT_FOUND )
2413 {
2414 return wxNOT_FOUND;
f2d76237 2415 }
c4608a8a
VZ
2416
2417 wxGridCellRenderer *renderer = GetRenderer(index);
2418 wxGridCellRenderer *rendererOld = renderer;
2419 renderer = renderer->Clone();
2420 rendererOld->DecRef();
2421
2422 wxGridCellEditor *editor = GetEditor(index);
2423 wxGridCellEditor *editorOld = editor;
2424 editor = editor->Clone();
2425 editorOld->DecRef();
2426
2427 // do it even if there are no parameters to reset them to defaults
2428 wxString params = typeName.AfterFirst(_T(':'));
2429 renderer->SetParameters(params);
2430 editor->SetParameters(params);
2431
2432 // register the new typename
c4608a8a
VZ
2433 RegisterDataType(typeName, renderer, editor);
2434
2435 // we just registered it, it's the last one
2436 index = m_typeinfo.GetCount() - 1;
f2d76237
RD
2437 }
2438
c4608a8a 2439 return index;
f2d76237
RD
2440}
2441
2442wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
2443{
2444 wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
faec5a43
SN
2445 if (renderer)
2446 renderer->IncRef();
f2d76237
RD
2447 return renderer;
2448}
2449
0b190b0f 2450wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
f2d76237
RD
2451{
2452 wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
faec5a43
SN
2453 if (editor)
2454 editor->IncRef();
f2d76237
RD
2455 return editor;
2456}
2457
758cbedf
VZ
2458// ----------------------------------------------------------------------------
2459// wxGridTableBase
2460// ----------------------------------------------------------------------------
2461
f85afd4e
MB
2462IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
2463
2464
2465wxGridTableBase::wxGridTableBase()
f85afd4e
MB
2466{
2467 m_view = (wxGrid *) NULL;
b99be8fb 2468 m_attrProvider = (wxGridCellAttrProvider *) NULL;
f85afd4e
MB
2469}
2470
2471wxGridTableBase::~wxGridTableBase()
2472{
b99be8fb
VZ
2473 delete m_attrProvider;
2474}
2475
2476void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
2477{
2478 delete m_attrProvider;
2479 m_attrProvider = attrProvider;
f85afd4e
MB
2480}
2481
f2d76237
RD
2482bool wxGridTableBase::CanHaveAttributes()
2483{
2484 if ( ! GetAttrProvider() )
2485 {
2486 // use the default attr provider by default
2487 SetAttrProvider(new wxGridCellAttrProvider);
2488 }
2489 return TRUE;
2490}
2491
b99be8fb
VZ
2492wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col)
2493{
2494 if ( m_attrProvider )
2495 return m_attrProvider->GetAttr(row, col);
2496 else
2497 return (wxGridCellAttr *)NULL;
2498}
2499
758cbedf 2500void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
b99be8fb
VZ
2501{
2502 if ( m_attrProvider )
2503 {
2504 m_attrProvider->SetAttr(attr, row, col);
2505 }
2506 else
2507 {
2508 // as we take ownership of the pointer and don't store it, we must
2509 // free it now
39bcce60 2510 wxSafeDecRef(attr);
b99be8fb
VZ
2511 }
2512}
2513
758cbedf
VZ
2514void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
2515{
2516 if ( m_attrProvider )
2517 {
2518 m_attrProvider->SetRowAttr(attr, row);
2519 }
2520 else
2521 {
2522 // as we take ownership of the pointer and don't store it, we must
2523 // free it now
39bcce60 2524 wxSafeDecRef(attr);
758cbedf
VZ
2525 }
2526}
2527
2528void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
2529{
2530 if ( m_attrProvider )
2531 {
2532 m_attrProvider->SetColAttr(attr, col);
2533 }
2534 else
2535 {
2536 // as we take ownership of the pointer and don't store it, we must
2537 // free it now
39bcce60 2538 wxSafeDecRef(attr);
758cbedf
VZ
2539 }
2540}
2541
aa5e1f75
SN
2542bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos),
2543 size_t WXUNUSED(numRows) )
f85afd4e 2544{
f6bcfd97 2545 wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
8f177c8e 2546
f85afd4e
MB
2547 return FALSE;
2548}
2549
aa5e1f75 2550bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) )
f85afd4e 2551{
f6bcfd97 2552 wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
8f177c8e 2553
f85afd4e
MB
2554 return FALSE;
2555}
2556
aa5e1f75
SN
2557bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos),
2558 size_t WXUNUSED(numRows) )
f85afd4e 2559{
f6bcfd97 2560 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
8f177c8e 2561
f85afd4e
MB
2562 return FALSE;
2563}
2564
aa5e1f75
SN
2565bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos),
2566 size_t WXUNUSED(numCols) )
f85afd4e 2567{
f6bcfd97 2568 wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
8f177c8e 2569
f85afd4e
MB
2570 return FALSE;
2571}
2572
aa5e1f75 2573bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) )
f85afd4e 2574{
f6bcfd97 2575 wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
8f177c8e 2576
f85afd4e
MB
2577 return FALSE;
2578}
2579
aa5e1f75
SN
2580bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos),
2581 size_t WXUNUSED(numCols) )
f85afd4e 2582{
f6bcfd97 2583 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
8f177c8e 2584
f85afd4e
MB
2585 return FALSE;
2586}
2587
2588
2589wxString wxGridTableBase::GetRowLabelValue( int row )
2590{
2591 wxString s;
f2d76237
RD
2592 s << row + 1; // RD: Starting the rows at zero confuses users, no matter
2593 // how much it makes sense to us geeks.
f85afd4e
MB
2594 return s;
2595}
2596
2597wxString wxGridTableBase::GetColLabelValue( int col )
2598{
2599 // default col labels are:
2600 // cols 0 to 25 : A-Z
2601 // cols 26 to 675 : AA-ZZ
2602 // etc.
2603
2604 wxString s;
2605 unsigned int i, n;
2606 for ( n = 1; ; n++ )
2607 {
f0102d2a 2608 s += (_T('A') + (wxChar)( col%26 ));
f85afd4e
MB
2609 col = col/26 - 1;
2610 if ( col < 0 ) break;
2611 }
2612
2613 // reverse the string...
2614 wxString s2;
2615 for ( i = 0; i < n; i++ )
2616 {
2617 s2 += s[n-i-1];
2618 }
2619
2620 return s2;
2621}
2622
2623
f2d76237
RD
2624wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
2625{
816be743 2626 return wxGRID_VALUE_STRING;
f2d76237
RD
2627}
2628
2629bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
2630 const wxString& typeName )
2631{
816be743 2632 return typeName == wxGRID_VALUE_STRING;
f2d76237
RD
2633}
2634
2635bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
2636{
2637 return CanGetValueAs(row, col, typeName);
2638}
2639
2640long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
2641{
2642 return 0;
2643}
2644
2645double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
2646{
2647 return 0.0;
2648}
2649
2650bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
2651{
2652 return FALSE;
2653}
2654
2655void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
2656 long WXUNUSED(value) )
2657{
2658}
2659
2660void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
2661 double WXUNUSED(value) )
2662{
2663}
2664
2665void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
2666 bool WXUNUSED(value) )
2667{
2668}
2669
2670
2671void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
2672 const wxString& WXUNUSED(typeName) )
2673{
2674 return NULL;
2675}
2676
2677void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
2678 const wxString& WXUNUSED(typeName),
2679 void* WXUNUSED(value) )
2680{
2681}
2682
f85afd4e
MB
2683//////////////////////////////////////////////////////////////////////
2684//
2685// Message class for the grid table to send requests and notifications
2686// to the grid view
2687//
2688
2689wxGridTableMessage::wxGridTableMessage()
2690{
2691 m_table = (wxGridTableBase *) NULL;
2692 m_id = -1;
2693 m_comInt1 = -1;
2694 m_comInt2 = -1;
2695}
2696
2697wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
2698 int commandInt1, int commandInt2 )
2699{
2700 m_table = table;
2701 m_id = id;
2702 m_comInt1 = commandInt1;
2703 m_comInt2 = commandInt2;
2704}
2705
2706
2707
2708//////////////////////////////////////////////////////////////////////
2709//
2710// A basic grid table for string data. An object of this class will
2711// created by wxGrid if you don't specify an alternative table class.
2712//
2713
223d09f6 2714WX_DEFINE_OBJARRAY(wxGridStringArray)
f85afd4e
MB
2715
2716IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
2717
2718wxGridStringTable::wxGridStringTable()
2719 : wxGridTableBase()
2720{
2721}
2722
2723wxGridStringTable::wxGridStringTable( int numRows, int numCols )
2724 : wxGridTableBase()
2725{
2726 int row, col;
8f177c8e 2727
f85afd4e
MB
2728 m_data.Alloc( numRows );
2729
2730 wxArrayString sa;
2731 sa.Alloc( numCols );
2732 for ( col = 0; col < numCols; col++ )
2733 {
2734 sa.Add( wxEmptyString );
2735 }
8f177c8e 2736
f85afd4e
MB
2737 for ( row = 0; row < numRows; row++ )
2738 {
2739 m_data.Add( sa );
2740 }
2741}
2742
2743wxGridStringTable::~wxGridStringTable()
2744{
2745}
2746
e32352cf 2747int wxGridStringTable::GetNumberRows()
f85afd4e
MB
2748{
2749 return m_data.GetCount();
2750}
2751
e32352cf 2752int wxGridStringTable::GetNumberCols()
f85afd4e
MB
2753{
2754 if ( m_data.GetCount() > 0 )
2755 return m_data[0].GetCount();
2756 else
2757 return 0;
2758}
2759
2760wxString wxGridStringTable::GetValue( int row, int col )
2761{
831243b1 2762 wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
af547d51
VZ
2763 _T("invalid row or column index in wxGridStringTable") );
2764
f85afd4e
MB
2765 return m_data[row][col];
2766}
2767
f2d76237 2768void wxGridStringTable::SetValue( int row, int col, const wxString& value )
f85afd4e 2769{
831243b1 2770 wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
af547d51
VZ
2771 _T("invalid row or column index in wxGridStringTable") );
2772
f2d76237 2773 m_data[row][col] = value;
f85afd4e
MB
2774}
2775
2776bool wxGridStringTable::IsEmptyCell( int row, int col )
2777{
831243b1 2778 wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
af547d51
VZ
2779 _T("invalid row or column index in wxGridStringTable") );
2780
f85afd4e
MB
2781 return (m_data[row][col] == wxEmptyString);
2782}
2783
f85afd4e
MB
2784void wxGridStringTable::Clear()
2785{
2786 int row, col;
2787 int numRows, numCols;
8f177c8e 2788
f85afd4e
MB
2789 numRows = m_data.GetCount();
2790 if ( numRows > 0 )
2791 {
2792 numCols = m_data[0].GetCount();
2793
2794 for ( row = 0; row < numRows; row++ )
2795 {
2796 for ( col = 0; col < numCols; col++ )
2797 {
2798 m_data[row][col] = wxEmptyString;
2799 }
2800 }
2801 }
2802}
2803
2804
2805bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
2806{
2807 size_t row, col;
2808
2809 size_t curNumRows = m_data.GetCount();
f6bcfd97
BP
2810 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
2811 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 2812
f85afd4e
MB
2813 if ( pos >= curNumRows )
2814 {
2815 return AppendRows( numRows );
2816 }
8f177c8e 2817
f85afd4e
MB
2818 wxArrayString sa;
2819 sa.Alloc( curNumCols );
2820 for ( col = 0; col < curNumCols; col++ )
2821 {
2822 sa.Add( wxEmptyString );
2823 }
2824
2825 for ( row = pos; row < pos + numRows; row++ )
2826 {
2827 m_data.Insert( sa, row );
2828 }
f85afd4e
MB
2829 if ( GetView() )
2830 {
2831 wxGridTableMessage msg( this,
2832 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
2833 pos,
2834 numRows );
8f177c8e 2835
f85afd4e
MB
2836 GetView()->ProcessTableMessage( msg );
2837 }
2838
2839 return TRUE;
2840}
2841
2842bool wxGridStringTable::AppendRows( size_t numRows )
2843{
2844 size_t row, col;
2845
2846 size_t curNumRows = m_data.GetCount();
f6bcfd97
BP
2847 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
2848 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 2849
f85afd4e
MB
2850 wxArrayString sa;
2851 if ( curNumCols > 0 )
2852 {
2853 sa.Alloc( curNumCols );
2854 for ( col = 0; col < curNumCols; col++ )
2855 {
2856 sa.Add( wxEmptyString );
2857 }
2858 }
8f177c8e 2859
f85afd4e
MB
2860 for ( row = 0; row < numRows; row++ )
2861 {
2862 m_data.Add( sa );
2863 }
2864
2865 if ( GetView() )
2866 {
2867 wxGridTableMessage msg( this,
2868 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
2869 numRows );
8f177c8e 2870
f85afd4e
MB
2871 GetView()->ProcessTableMessage( msg );
2872 }
2873
8f177c8e 2874 return TRUE;
f85afd4e
MB
2875}
2876
2877bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
2878{
2879 size_t n;
2880
2881 size_t curNumRows = m_data.GetCount();
8f177c8e 2882
f85afd4e
MB
2883 if ( pos >= curNumRows )
2884 {
bd3c6758 2885 wxString errmsg;
f6bcfd97 2886 errmsg.Printf(wxT("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\nPos value is invalid for present table with %d rows"),
bd3c6758 2887 pos, numRows, curNumRows );
f6bcfd97 2888 wxFAIL_MSG( errmsg );
f85afd4e
MB
2889 return FALSE;
2890 }
2891
2892 if ( numRows > curNumRows - pos )
2893 {
2894 numRows = curNumRows - pos;
2895 }
8f177c8e 2896
f85afd4e
MB
2897 if ( numRows >= curNumRows )
2898 {
2899 m_data.Empty(); // don't release memory just yet
2900 }
2901 else
2902 {
2903 for ( n = 0; n < numRows; n++ )
2904 {
2905 m_data.Remove( pos );
2906 }
2907 }
f85afd4e
MB
2908 if ( GetView() )
2909 {
2910 wxGridTableMessage msg( this,
2911 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
2912 pos,
2913 numRows );
8f177c8e 2914
f85afd4e
MB
2915 GetView()->ProcessTableMessage( msg );
2916 }
2917
8f177c8e 2918 return TRUE;
f85afd4e
MB
2919}
2920
2921bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
2922{
2923 size_t row, col;
2924
2925 size_t curNumRows = m_data.GetCount();
f6bcfd97
BP
2926 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
2927 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 2928
f85afd4e
MB
2929 if ( pos >= curNumCols )
2930 {
2931 return AppendCols( numCols );
2932 }
2933
2934 for ( row = 0; row < curNumRows; row++ )
2935 {
2936 for ( col = pos; col < pos + numCols; col++ )
2937 {
2938 m_data[row].Insert( wxEmptyString, col );
2939 }
2940 }
f85afd4e
MB
2941 if ( GetView() )
2942 {
2943 wxGridTableMessage msg( this,
2944 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
2945 pos,
2946 numCols );
8f177c8e 2947
f85afd4e
MB
2948 GetView()->ProcessTableMessage( msg );
2949 }
2950
2951 return TRUE;
2952}
2953
2954bool wxGridStringTable::AppendCols( size_t numCols )
2955{
2956 size_t row, n;
2957
2958 size_t curNumRows = m_data.GetCount();
f6bcfd97 2959#if 0
f85afd4e
MB
2960 if ( !curNumRows )
2961 {
2962 // TODO: something better than this ?
2963 //
f6bcfd97 2964 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") );
f85afd4e
MB
2965 return FALSE;
2966 }
f6bcfd97 2967#endif
8f177c8e 2968
f85afd4e
MB
2969 for ( row = 0; row < curNumRows; row++ )
2970 {
2971 for ( n = 0; n < numCols; n++ )
2972 {
2973 m_data[row].Add( wxEmptyString );
2974 }
2975 }
2976
2977 if ( GetView() )
2978 {
2979 wxGridTableMessage msg( this,
2980 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
2981 numCols );
8f177c8e 2982
f85afd4e
MB
2983 GetView()->ProcessTableMessage( msg );
2984 }
2985
2986 return TRUE;
2987}
2988
2989bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
2990{
2991 size_t row, n;
2992
2993 size_t curNumRows = m_data.GetCount();
f6bcfd97
BP
2994 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
2995 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 2996
f85afd4e
MB
2997 if ( pos >= curNumCols )
2998 {
bd3c6758 2999 wxString errmsg;
f6bcfd97 3000 errmsg.Printf( wxT("Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\nPos value is invalid for present table with %d cols"),
bd3c6758 3001 pos, numCols, curNumCols );
f6bcfd97 3002 wxFAIL_MSG( errmsg );
8f177c8e 3003 return FALSE;
f85afd4e
MB
3004 }
3005
3006 if ( numCols > curNumCols - pos )
3007 {
8f177c8e 3008 numCols = curNumCols - pos;
f85afd4e
MB
3009 }
3010
3011 for ( row = 0; row < curNumRows; row++ )
3012 {
3013 if ( numCols >= curNumCols )
3014 {
3015 m_data[row].Clear();
3016 }
3017 else
3018 {
3019 for ( n = 0; n < numCols; n++ )
3020 {
3021 m_data[row].Remove( pos );
3022 }
3023 }
3024 }
f85afd4e
MB
3025 if ( GetView() )
3026 {
3027 wxGridTableMessage msg( this,
3028 wxGRIDTABLE_NOTIFY_COLS_DELETED,
3029 pos,
3030 numCols );
8f177c8e 3031
f85afd4e
MB
3032 GetView()->ProcessTableMessage( msg );
3033 }
3034
8f177c8e 3035 return TRUE;
f85afd4e
MB
3036}
3037
3038wxString wxGridStringTable::GetRowLabelValue( int row )
3039{
3040 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3041 {
3042 // using default label
3043 //
3044 return wxGridTableBase::GetRowLabelValue( row );
3045 }
3046 else
3047 {
3048 return m_rowLabels[ row ];
3049 }
3050}
3051
3052wxString wxGridStringTable::GetColLabelValue( int col )
3053{
3054 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3055 {
3056 // using default label
3057 //
3058 return wxGridTableBase::GetColLabelValue( col );
3059 }
3060 else
3061 {
3062 return m_colLabels[ col ];
3063 }
3064}
3065
3066void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
3067{
3068 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3069 {
3070 int n = m_rowLabels.GetCount();
3071 int i;
3072 for ( i = n; i <= row; i++ )
3073 {
3074 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
3075 }
3076 }
3077
3078 m_rowLabels[row] = value;
3079}
3080
3081void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
3082{
3083 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3084 {
3085 int n = m_colLabels.GetCount();
3086 int i;
3087 for ( i = n; i <= col; i++ )
3088 {
3089 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
3090 }
3091 }
3092
3093 m_colLabels[col] = value;
3094}
3095
3096
3097
f85afd4e 3098//////////////////////////////////////////////////////////////////////
2d66e025
MB
3099//////////////////////////////////////////////////////////////////////
3100
3101IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
3102
3103BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
3104 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
3105 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
3106 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
f6bcfd97 3107 EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp )
2d66e025
MB
3108END_EVENT_TABLE()
3109
60ff3b99
VZ
3110wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
3111 wxWindowID id,
2d66e025 3112 const wxPoint &pos, const wxSize &size )
ebd773c6 3113 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
2d66e025
MB
3114{
3115 m_owner = parent;
3116}
3117
aa5e1f75 3118void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
2d66e025
MB
3119{
3120 wxPaintDC dc(this);
3121
3122 // NO - don't do this because it will set both the x and y origin
3123 // coords to match the parent scrolled window and we just want to
3124 // set the y coord - MB
3125 //
3126 // m_owner->PrepareDC( dc );
60ff3b99 3127
790ad94f 3128 int x, y;
2d66e025
MB
3129 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3130 dc.SetDeviceOrigin( 0, -y );
60ff3b99 3131
2d66e025
MB
3132 m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
3133 m_owner->DrawRowLabels( dc );
3134}
3135
3136
3137void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
3138{
3139 m_owner->ProcessRowLabelMouseEvent( event );
3140}
3141
3142
3143// This seems to be required for wxMotif otherwise the mouse
3144// cursor must be in the cell edit control to get key events
3145//
3146void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
3147{
ffdd3c98 3148 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
2d66e025
MB
3149}
3150
f6bcfd97
BP
3151void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event )
3152{
ffdd3c98 3153 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
f6bcfd97
BP
3154}
3155
2d66e025
MB
3156
3157
3158//////////////////////////////////////////////////////////////////////
3159
3160IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
3161
3162BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
3163 EVT_PAINT( wxGridColLabelWindow::OnPaint )
3164 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
3165 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
f6bcfd97 3166 EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp )
2d66e025
MB
3167END_EVENT_TABLE()
3168
60ff3b99
VZ
3169wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
3170 wxWindowID id,
2d66e025 3171 const wxPoint &pos, const wxSize &size )
ebd773c6 3172 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
2d66e025
MB
3173{
3174 m_owner = parent;
3175}
3176
aa5e1f75 3177void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
2d66e025
MB
3178{
3179 wxPaintDC dc(this);
3180
3181 // NO - don't do this because it will set both the x and y origin
3182 // coords to match the parent scrolled window and we just want to
3183 // set the x coord - MB
3184 //
3185 // m_owner->PrepareDC( dc );
60ff3b99 3186
790ad94f 3187 int x, y;
2d66e025
MB
3188 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3189 dc.SetDeviceOrigin( -x, 0 );
3190
60ff3b99
VZ
3191 m_owner->CalcColLabelsExposed( GetUpdateRegion() );
3192 m_owner->DrawColLabels( dc );
2d66e025
MB
3193}
3194
3195
3196void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
3197{
3198 m_owner->ProcessColLabelMouseEvent( event );
3199}
3200
3201
3202// This seems to be required for wxMotif otherwise the mouse
3203// cursor must be in the cell edit control to get key events
3204//
3205void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
3206{
ffdd3c98 3207 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
2d66e025
MB
3208}
3209
f6bcfd97
BP
3210void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event )
3211{
ffdd3c98 3212 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
f6bcfd97
BP
3213}
3214
2d66e025
MB
3215
3216
3217//////////////////////////////////////////////////////////////////////
3218
3219IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
3220
3221BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
3222 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
d2fdd8d2 3223 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
2d66e025 3224 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
f6bcfd97 3225 EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp )
2d66e025
MB
3226END_EVENT_TABLE()
3227
60ff3b99
VZ
3228wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
3229 wxWindowID id,
2d66e025 3230 const wxPoint &pos, const wxSize &size )
ebd773c6 3231 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
2d66e025
MB
3232{
3233 m_owner = parent;
3234}
3235
d2fdd8d2
RR
3236void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3237{
3238 wxPaintDC dc(this);
b99be8fb 3239
d2fdd8d2
RR
3240 int client_height = 0;
3241 int client_width = 0;
3242 GetClientSize( &client_width, &client_height );
b99be8fb 3243
d2fdd8d2
RR
3244 dc.SetPen( *wxBLACK_PEN );
3245 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
3246 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
b99be8fb 3247
d2fdd8d2
RR
3248 dc.SetPen( *wxWHITE_PEN );
3249 dc.DrawLine( 0, 0, client_width, 0 );
3250 dc.DrawLine( 0, 0, 0, client_height );
3251}
3252
2d66e025
MB
3253
3254void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
3255{
3256 m_owner->ProcessCornerLabelMouseEvent( event );
3257}
3258
3259
3260// This seems to be required for wxMotif otherwise the mouse
3261// cursor must be in the cell edit control to get key events
3262//
3263void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
3264{
ffdd3c98 3265 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
2d66e025
MB
3266}
3267
f6bcfd97
BP
3268void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event )
3269{
ffdd3c98 3270 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
f6bcfd97
BP
3271}
3272
2d66e025
MB
3273
3274
f85afd4e
MB
3275//////////////////////////////////////////////////////////////////////
3276
2d66e025
MB
3277IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
3278
3279BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
3280 EVT_PAINT( wxGridWindow::OnPaint )
2d66e025
MB
3281 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
3282 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
f6bcfd97 3283 EVT_KEY_UP( wxGridWindow::OnKeyUp )
2796cce3 3284 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
2d66e025
MB
3285END_EVENT_TABLE()
3286
60ff3b99
VZ
3287wxGridWindow::wxGridWindow( wxGrid *parent,
3288 wxGridRowLabelWindow *rowLblWin,
2d66e025
MB
3289 wxGridColLabelWindow *colLblWin,
3290 wxWindowID id, const wxPoint &pos, const wxSize &size )
ebd773c6 3291 : wxPanel( parent, id, pos, size, wxWANTS_CHARS, "grid window" )
2d66e025
MB
3292{
3293 m_owner = parent;
3294 m_rowLabelWin = rowLblWin;
3295 m_colLabelWin = colLblWin;
2d66e025
MB
3296 SetBackgroundColour( "WHITE" );
3297}
3298
3299
3300wxGridWindow::~wxGridWindow()
3301{
3302}
3303
3304
3305void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
3306{
3307 wxPaintDC dc( this );
3308 m_owner->PrepareDC( dc );
796df70a
SN
3309 wxRegion reg = GetUpdateRegion();
3310 m_owner->CalcCellsExposed( reg );
2d66e025 3311 m_owner->DrawGridCellArea( dc );
9496deb5 3312#if WXGRID_DRAW_LINES
796df70a
SN
3313 m_owner->DrawAllGridLines( dc, reg );
3314#endif
a5777624 3315 m_owner->DrawGridSpace( dc );
b3a7510d 3316 m_owner->DrawHighlight( dc );
2d66e025
MB
3317}
3318
3319
3320void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
3321{
3322 wxPanel::ScrollWindow( dx, dy, rect );
3323 m_rowLabelWin->ScrollWindow( 0, dy, rect );
3324 m_colLabelWin->ScrollWindow( dx, 0, rect );
3325}
3326
3327
3328void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
3329{
3330 m_owner->ProcessGridCellMouseEvent( event );
3331}
3332
3333
f6bcfd97 3334// This seems to be required for wxMotif/wxGTK otherwise the mouse
2d66e025
MB
3335// cursor must be in the cell edit control to get key events
3336//
3337void wxGridWindow::OnKeyDown( wxKeyEvent& event )
3338{
ffdd3c98 3339 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
2d66e025 3340}
f85afd4e 3341
f6bcfd97
BP
3342void wxGridWindow::OnKeyUp( wxKeyEvent& event )
3343{
ffdd3c98 3344 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
f6bcfd97 3345}
7c8a8ad5 3346
aa5e1f75 3347void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
8dd4f536 3348{
8dd4f536 3349}
025562fe 3350
2d66e025
MB
3351
3352//////////////////////////////////////////////////////////////////////
3353
07296f0b 3354
2d66e025
MB
3355IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
3356
3357BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
f85afd4e
MB
3358 EVT_PAINT( wxGrid::OnPaint )
3359 EVT_SIZE( wxGrid::OnSize )
f85afd4e 3360 EVT_KEY_DOWN( wxGrid::OnKeyDown )
f6bcfd97 3361 EVT_KEY_UP( wxGrid::OnKeyUp )
2796cce3 3362 EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground )
f85afd4e 3363END_EVENT_TABLE()
8f177c8e 3364
2d66e025
MB
3365wxGrid::wxGrid( wxWindow *parent,
3366 wxWindowID id,
3367 const wxPoint& pos,
3368 const wxSize& size,
3369 long style,
3370 const wxString& name )
ebd773c6 3371 : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ),
af547d51
VZ
3372 m_colMinWidths(GRID_HASH_SIZE),
3373 m_rowMinHeights(GRID_HASH_SIZE)
2d66e025
MB
3374{
3375 Create();
58dd5b3b
MB
3376}
3377
3378
3379wxGrid::~wxGrid()
3380{
0a976765 3381 ClearAttrCache();
39bcce60 3382 wxSafeDecRef(m_defaultCellAttr);
0a976765
VZ
3383
3384#ifdef DEBUG_ATTR_CACHE
3385 size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
3386 wxPrintf(_T("wxGrid attribute cache statistics: "
3387 "total: %u, hits: %u (%u%%)\n"),
3388 total, gs_nAttrCacheHits,
3389 total ? (gs_nAttrCacheHits*100) / total : 0);
3390#endif
3391
2796cce3
RD
3392 if (m_ownTable)
3393 delete m_table;
f2d76237
RD
3394
3395 delete m_typeRegistry;
b5808881 3396 delete m_selection;
58dd5b3b
MB
3397}
3398
2d66e025 3399
58dd5b3b
MB
3400//
3401// ----- internal init and update functions
3402//
3403
3404void wxGrid::Create()
f0102d2a 3405{
4634a5d6 3406 m_created = FALSE; // set to TRUE by CreateGrid
4634a5d6
MB
3407
3408 m_table = (wxGridTableBase *) NULL;
2796cce3 3409 m_ownTable = FALSE;
2c9a89e0
RD
3410
3411 m_cellEditCtrlEnabled = FALSE;
4634a5d6 3412
2796cce3
RD
3413 m_defaultCellAttr = new wxGridCellAttr;
3414 m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
f2d76237
RD
3415
3416 // Set default cell attributes
3417 m_defaultCellAttr->SetFont(GetFont());
4c7277db 3418 m_defaultCellAttr->SetAlignment(wxALIGN_LEFT, wxALIGN_TOP);
f2d76237
RD
3419 m_defaultCellAttr->SetTextColour(
3420 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
3421 m_defaultCellAttr->SetBackgroundColour(
3422 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
3423 m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
3424 m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
2796cce3
RD
3425
3426
4634a5d6
MB
3427 m_numRows = 0;
3428 m_numCols = 0;
3429 m_currentCellCoords = wxGridNoCellCoords;
b99be8fb 3430
18f9565d
MB
3431 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
3432 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
2d66e025 3433
c4608a8a 3434 // create the type registry
f2d76237 3435 m_typeRegistry = new wxGridTypeRegistry;
b5808881 3436 m_selection = 0;
f2d76237 3437 // subwindow components that make up the wxGrid
7807d81c
MB
3438 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
3439 -1,
18f9565d
MB
3440 wxDefaultPosition,
3441 wxDefaultSize );
7807d81c 3442
60ff3b99
VZ
3443 m_rowLabelWin = new wxGridRowLabelWindow( this,
3444 -1,
18f9565d
MB
3445 wxDefaultPosition,
3446 wxDefaultSize );
2d66e025
MB
3447
3448 m_colLabelWin = new wxGridColLabelWindow( this,
3449 -1,
18f9565d
MB
3450 wxDefaultPosition,
3451 wxDefaultSize );
60ff3b99 3452
60ff3b99
VZ
3453 m_gridWin = new wxGridWindow( this,
3454 m_rowLabelWin,
3455 m_colLabelWin,
3456 -1,
18f9565d 3457 wxDefaultPosition,
2d66e025
MB
3458 wxDefaultSize );
3459
3460 SetTargetWindow( m_gridWin );
2d66e025 3461}
f85afd4e 3462
2d66e025 3463
b5808881
SN
3464bool wxGrid::CreateGrid( int numRows, int numCols,
3465 wxGrid::wxGridSelectionModes selmode )
2d66e025 3466{
f6bcfd97
BP
3467 wxCHECK_MSG( !m_created,
3468 FALSE,
3469 wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
3470
3471 m_numRows = numRows;
3472 m_numCols = numCols;
3473
3474 m_table = new wxGridStringTable( m_numRows, m_numCols );
3475 m_table->SetView( this );
3476 m_ownTable = TRUE;
3477 m_selection = new wxGridSelection( this, selmode );
3478 Init();
3479 m_created = TRUE;
2d66e025 3480
2796cce3
RD
3481 return m_created;
3482}
3483
f1567cdd
SN
3484void wxGrid::SetSelectionMode(wxGrid::wxGridSelectionModes selmode)
3485{
3486 if ( !m_created )
3487 {
3488 wxFAIL_MSG( wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") );
3489 }
3490 else
3491 m_selection->SetSelectionMode( selmode );
3492}
3493
043d16b2
SN
3494bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership,
3495 wxGrid::wxGridSelectionModes selmode )
2796cce3
RD
3496{
3497 if ( m_created )
3498 {
fb295790
RD
3499 // RD: Actually, this should probably be allowed. I think it would be
3500 // nice to be able to switch multiple Tables in and out of a single
3501 // View at runtime. Is there anything in the implmentation that would
3502 // prevent this?
3503
d95b0c2b 3504 // At least, you now have to cope with m_selection
2796cce3
RD
3505 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
3506 return FALSE;
3507 }
3508 else
3509 {
3510 m_numRows = table->GetNumberRows();
3511 m_numCols = table->GetNumberCols();
3512
3513 m_table = table;
3514 m_table->SetView( this );
3515 if (takeOwnership)
3516 m_ownTable = TRUE;
043d16b2 3517 m_selection = new wxGridSelection( this, selmode );
f6bcfd97 3518 Init();
2d66e025
MB
3519 m_created = TRUE;
3520 }
f85afd4e 3521
2d66e025 3522 return m_created;
f85afd4e
MB
3523}
3524
2d66e025 3525
f85afd4e
MB
3526void wxGrid::Init()
3527{
f85afd4e
MB
3528 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
3529 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
3530
60ff3b99
VZ
3531 if ( m_rowLabelWin )
3532 {
3533 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
3534 }
3535 else
3536 {
3537 m_labelBackgroundColour = wxColour( _T("WHITE") );
3538 }
3539
3540 m_labelTextColour = wxColour( _T("BLACK") );
f85afd4e 3541
0a976765
VZ
3542 // init attr cache
3543 m_attrCache.row = -1;
3544
f85afd4e
MB
3545 // TODO: something better than this ?
3546 //
3547 m_labelFont = this->GetFont();
3548 m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 );
8f177c8e 3549
4c7277db
MB
3550 m_rowLabelHorizAlign = wxALIGN_LEFT;
3551 m_rowLabelVertAlign = wxALIGN_CENTRE;
f85afd4e 3552
4c7277db
MB
3553 m_colLabelHorizAlign = wxALIGN_CENTRE;
3554 m_colLabelVertAlign = wxALIGN_TOP;
f85afd4e 3555
f85afd4e 3556 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
1f1ce288
MB
3557 m_defaultRowHeight = m_gridWin->GetCharHeight();
3558
d2fdd8d2 3559#if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
1f1ce288
MB
3560 m_defaultRowHeight += 8;
3561#else
3562 m_defaultRowHeight += 4;
3563#endif
3564
2d66e025 3565 m_gridLineColour = wxColour( 128, 128, 255 );
f85afd4e 3566 m_gridLinesEnabled = TRUE;
f6bcfd97 3567 m_cellHighlightColour = m_gridLineColour;
8f177c8e 3568
58dd5b3b 3569 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
e2b42eeb 3570 m_winCapture = (wxWindow *)NULL;
6e8524b1
MB
3571 m_canDragRowSize = TRUE;
3572 m_canDragColSize = TRUE;
4cfa5de6 3573 m_canDragGridSize = TRUE;
f85afd4e
MB
3574 m_dragLastPos = -1;
3575 m_dragRowOrCol = -1;
3576 m_isDragging = FALSE;
07296f0b 3577 m_startDragPos = wxDefaultPosition;
f85afd4e 3578
07296f0b 3579 m_waitForSlowClick = FALSE;
025562fe 3580
f85afd4e
MB
3581 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
3582 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
3583
3584 m_currentCellCoords = wxGridNoCellCoords;
f85afd4e 3585
b5808881
SN
3586 m_selectingTopLeft = wxGridNoCellCoords;
3587 m_selectingBottomRight = wxGridNoCellCoords;
2796cce3
RD
3588 m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT);
3589 m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
8f177c8e 3590
f85afd4e
MB
3591 m_editable = TRUE; // default for whole grid
3592
2d66e025
MB
3593 m_inOnKeyDown = FALSE;
3594 m_batchCount = 0;
3c79cf49 3595
266e8367
VZ
3596 m_extraWidth =
3597 m_extraHeight = 50;
3598
3c79cf49 3599 CalcDimensions();
7c1cb261
VZ
3600}
3601
3602// ----------------------------------------------------------------------------
3603// the idea is to call these functions only when necessary because they create
3604// quite big arrays which eat memory mostly unnecessary - in particular, if
3605// default widths/heights are used for all rows/columns, we may not use these
3606// arrays at all
3607//
3608// with some extra code, it should be possible to only store the
3609// widths/heights different from default ones but this will be done later...
3610// ----------------------------------------------------------------------------
3611
3612void wxGrid::InitRowHeights()
3613{
3614 m_rowHeights.Empty();
3615 m_rowBottoms.Empty();
3616
3617 m_rowHeights.Alloc( m_numRows );
3618 m_rowBottoms.Alloc( m_numRows );
3619
3620 int rowBottom = 0;
3621 for ( int i = 0; i < m_numRows; i++ )
3622 {
3623 m_rowHeights.Add( m_defaultRowHeight );
3624 rowBottom += m_defaultRowHeight;
3625 m_rowBottoms.Add( rowBottom );
3626 }
3627}
3628
3629void wxGrid::InitColWidths()
3630{
3631 m_colWidths.Empty();
3632 m_colRights.Empty();
3633
3634 m_colWidths.Alloc( m_numCols );
3635 m_colRights.Alloc( m_numCols );
3636 int colRight = 0;
3637 for ( int i = 0; i < m_numCols; i++ )
3638 {
3639 m_colWidths.Add( m_defaultColWidth );
3640 colRight += m_defaultColWidth;
3641 m_colRights.Add( colRight );
3642 }
3643}
3644
3645int wxGrid::GetColWidth(int col) const
3646{
3647 return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col];
3648}
3649
3650int wxGrid::GetColLeft(int col) const
3651{
3652 return m_colRights.IsEmpty() ? col * m_defaultColWidth
3653 : m_colRights[col] - m_colWidths[col];
3654}
3655
3656int wxGrid::GetColRight(int col) const
3657{
3658 return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth
3659 : m_colRights[col];
3660}
3661
3662int wxGrid::GetRowHeight(int row) const
3663{
3664 return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row];
3665}
2d66e025 3666
7c1cb261
VZ
3667int wxGrid::GetRowTop(int row) const
3668{
3669 return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight
3670 : m_rowBottoms[row] - m_rowHeights[row];
f85afd4e
MB
3671}
3672
7c1cb261
VZ
3673int wxGrid::GetRowBottom(int row) const
3674{
3675 return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight
3676 : m_rowBottoms[row];
3677}
f85afd4e
MB
3678
3679void wxGrid::CalcDimensions()
3680{
f85afd4e 3681 int cw, ch;
2d66e025 3682 GetClientSize( &cw, &ch );
f85afd4e 3683
faec5a43
SN
3684 if ( m_colLabelWin->IsShown() )
3685 cw -= m_rowLabelWidth;
3686 if ( m_rowLabelWin->IsShown() )
3687 ch -= m_colLabelHeight;
60ff3b99 3688
faec5a43
SN
3689 // grid total size
3690 int w = m_numCols > 0 ? GetColRight(m_numCols - 1) + m_extraWidth + 1 : 0;
3691 int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) + m_extraHeight + 1 : 0;
3692
3693 // preserve (more or less) the previous position
3694 int x, y;
3695 GetViewStart( &x, &y );
3696 // maybe we don't need scrollbars at all? and if we do, transform w and h
3697 // from pixels into logical units
3698 if ( w <= cw )
3699 {
3700 w = 0; x= 0;
3701 }
3702 else
3703 {
3704 w = (w + GRID_SCROLL_LINE - 1)/GRID_SCROLL_LINE;
3705 if ( x >= w )
3706 x = w - 1;
f85afd4e 3707 }
faec5a43
SN
3708 if ( h <= ch )
3709 {
3710 h = 0; y = 0;
3711 }
3712 else
3713 {
3714 h = (h + GRID_SCROLL_LINE - 1)/GRID_SCROLL_LINE;
3715 if ( y >= h )
3716 y = h - 1;
3717 }
3718
3719 // do set scrollbar parameters
3720 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
389b961e 3721 w, h, x, y, (GetBatchCount() != 0));
f85afd4e
MB
3722}
3723
3724
7807d81c
MB
3725void wxGrid::CalcWindowSizes()
3726{
3727 int cw, ch;
3728 GetClientSize( &cw, &ch );
b99be8fb 3729
7807d81c
MB
3730 if ( m_cornerLabelWin->IsShown() )
3731 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
3732
3733 if ( m_colLabelWin->IsShown() )
3734 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
3735
3736 if ( m_rowLabelWin->IsShown() )
3737 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
3738
3739 if ( m_gridWin->IsShown() )
3740 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
3741}
3742
3743
f85afd4e
MB
3744// this is called when the grid table sends a message to say that it
3745// has been redimensioned
3746//
3747bool wxGrid::Redimension( wxGridTableMessage& msg )
3748{
3749 int i;
f6bcfd97 3750 bool result = FALSE;
8f177c8e 3751
f6bcfd97 3752#if 0
7c1cb261
VZ
3753 // if we were using the default widths/heights so far, we must change them
3754 // now
3755 if ( m_colWidths.IsEmpty() )
3756 {
3757 InitColWidths();
3758 }
3759
3760 if ( m_rowHeights.IsEmpty() )
3761 {
3762 InitRowHeights();
3763 }
f6bcfd97 3764#endif
7c1cb261 3765
f85afd4e
MB
3766 switch ( msg.GetId() )
3767 {
3768 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
3769 {
3770 size_t pos = msg.GetCommandInt();
3771 int numRows = msg.GetCommandInt2();
f6bcfd97 3772
f85afd4e 3773 m_numRows += numRows;
2d66e025 3774
f6bcfd97
BP
3775 if ( !m_rowHeights.IsEmpty() )
3776 {
3777 for ( i = 0; i < numRows; i++ )
3778 {
3779 m_rowHeights.Insert( m_defaultRowHeight, pos );
3780 m_rowBottoms.Insert( 0, pos );
3781 }
3782
3783 int bottom = 0;
3784 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
60ff3b99 3785
f6bcfd97
BP
3786 for ( i = pos; i < m_numRows; i++ )
3787 {
3788 bottom += m_rowHeights[i];
3789 m_rowBottoms[i] = bottom;
3790 }
3791 }
3792 if ( m_currentCellCoords == wxGridNoCellCoords )
3793 {
3794 // if we have just inserted cols into an empty grid the current
3795 // cell will be undefined...
3796 //
3797 SetCurrentCell( 0, 0 );
3798 }
3799 m_selection->UpdateRows( pos, numRows );
3800 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3801 if (attrProvider)
3802 attrProvider->UpdateAttrRows( pos, numRows );
3803
3804 if ( !GetBatchCount() )
2d66e025 3805 {
f6bcfd97
BP
3806 CalcDimensions();
3807 m_rowLabelWin->Refresh();
2d66e025 3808 }
f85afd4e 3809 }
f6bcfd97
BP
3810 result = TRUE;
3811 break;
f85afd4e
MB
3812
3813 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
3814 {
3815 int numRows = msg.GetCommandInt();
2d66e025 3816 int oldNumRows = m_numRows;
f85afd4e 3817 m_numRows += numRows;
2d66e025 3818
f6bcfd97
BP
3819 if ( !m_rowHeights.IsEmpty() )
3820 {
3821 for ( i = 0; i < numRows; i++ )
3822 {
3823 m_rowHeights.Add( m_defaultRowHeight );
3824 m_rowBottoms.Add( 0 );
3825 }
60ff3b99 3826
f6bcfd97
BP
3827 int bottom = 0;
3828 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
3829
3830 for ( i = oldNumRows; i < m_numRows; i++ )
3831 {
3832 bottom += m_rowHeights[i];
3833 m_rowBottoms[i] = bottom;
3834 }
3835 }
3836 if ( m_currentCellCoords == wxGridNoCellCoords )
3837 {
3838 // if we have just inserted cols into an empty grid the current
3839 // cell will be undefined...
3840 //
3841 SetCurrentCell( 0, 0 );
3842 }
3843 if ( !GetBatchCount() )
2d66e025 3844 {
f6bcfd97
BP
3845 CalcDimensions();
3846 m_rowLabelWin->Refresh();
2d66e025 3847 }
f85afd4e 3848 }
f6bcfd97
BP
3849 result = TRUE;
3850 break;
f85afd4e
MB
3851
3852 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
3853 {
3854 size_t pos = msg.GetCommandInt();
3855 int numRows = msg.GetCommandInt2();
f85afd4e
MB
3856 m_numRows -= numRows;
3857
f6bcfd97 3858 if ( !m_rowHeights.IsEmpty() )
f85afd4e 3859 {
f6bcfd97
BP
3860 for ( i = 0; i < numRows; i++ )
3861 {
3862 m_rowHeights.Remove( pos );
3863 m_rowBottoms.Remove( pos );
3864 }
2d66e025
MB
3865
3866 int h = 0;
3867 for ( i = 0; i < m_numRows; i++ )
3868 {
3869 h += m_rowHeights[i];
3870 m_rowBottoms[i] = h;
3871 }
f85afd4e 3872 }
f6bcfd97
BP
3873 if ( !m_numRows )
3874 {
3875 m_currentCellCoords = wxGridNoCellCoords;
3876 }
3877 else
3878 {
3879 if ( m_currentCellCoords.GetRow() >= m_numRows )
3880 m_currentCellCoords.Set( 0, 0 );
3881 }
3882 m_selection->UpdateRows( pos, -((int)numRows) );
3883 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3884 if (attrProvider) {
3885 attrProvider->UpdateAttrRows( pos, -((int)numRows) );
84912ef8
RD
3886// ifdef'd out following patch from Paul Gammans
3887#if 0
3ca6a5f0 3888 // No need to touch column attributes, unless we
f6bcfd97
BP
3889 // removed _all_ rows, in this case, we remove
3890 // all column attributes.
3891 // I hate to do this here, but the
3892 // needed data is not available inside UpdateAttrRows.
3893 if ( !GetNumberRows() )
3894 attrProvider->UpdateAttrCols( 0, -GetNumberCols() );
84912ef8 3895#endif
f6bcfd97
BP
3896 }
3897 if ( !GetBatchCount() )
3898 {
3899 CalcDimensions();
3900 m_rowLabelWin->Refresh();
3901 }
f85afd4e 3902 }
f6bcfd97
BP
3903 result = TRUE;
3904 break;
f85afd4e
MB
3905
3906 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
3907 {
3908 size_t pos = msg.GetCommandInt();
3909 int numCols = msg.GetCommandInt2();
f85afd4e 3910 m_numCols += numCols;
2d66e025 3911
f6bcfd97
BP
3912 if ( !m_colWidths.IsEmpty() )
3913 {
3914 for ( i = 0; i < numCols; i++ )
3915 {
3916 m_colWidths.Insert( m_defaultColWidth, pos );
3917 m_colRights.Insert( 0, pos );
3918 }
3919
3920 int right = 0;
3921 if ( pos > 0 ) right = m_colRights[pos-1];
60ff3b99 3922
f6bcfd97
BP
3923 for ( i = pos; i < m_numCols; i++ )
3924 {
3925 right += m_colWidths[i];
3926 m_colRights[i] = right;
3927 }
3928 }
3929 if ( m_currentCellCoords == wxGridNoCellCoords )
2d66e025 3930 {
f6bcfd97
BP
3931 // if we have just inserted cols into an empty grid the current
3932 // cell will be undefined...
3933 //
3934 SetCurrentCell( 0, 0 );
2d66e025 3935 }
f6bcfd97
BP
3936 m_selection->UpdateCols( pos, numCols );
3937 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3938 if (attrProvider)
3939 attrProvider->UpdateAttrCols( pos, numCols );
3940 if ( !GetBatchCount() )
3941 {
3942 CalcDimensions();
3943 m_colLabelWin->Refresh();
3944 }
3945
f85afd4e 3946 }
f6bcfd97
BP
3947 result = TRUE;
3948 break;
f85afd4e
MB
3949
3950 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
3951 {
3952 int numCols = msg.GetCommandInt();
2d66e025 3953 int oldNumCols = m_numCols;
f85afd4e 3954 m_numCols += numCols;
f6bcfd97
BP
3955 if ( !m_colWidths.IsEmpty() )
3956 {
3957 for ( i = 0; i < numCols; i++ )
3958 {
3959 m_colWidths.Add( m_defaultColWidth );
3960 m_colRights.Add( 0 );
3961 }
2d66e025 3962
f6bcfd97
BP
3963 int right = 0;
3964 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
60ff3b99 3965
f6bcfd97
BP
3966 for ( i = oldNumCols; i < m_numCols; i++ )
3967 {
3968 right += m_colWidths[i];
3969 m_colRights[i] = right;
3970 }
3971 }
3972 if ( m_currentCellCoords == wxGridNoCellCoords )
2d66e025 3973 {
f6bcfd97
BP
3974 // if we have just inserted cols into an empty grid the current
3975 // cell will be undefined...
3976 //
3977 SetCurrentCell( 0, 0 );
3978 }
3979 if ( !GetBatchCount() )
3980 {
3981 CalcDimensions();
3982 m_colLabelWin->Refresh();
2d66e025 3983 }
f85afd4e 3984 }
f6bcfd97
BP
3985 result = TRUE;
3986 break;
f85afd4e
MB
3987
3988 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
3989 {
3990 size_t pos = msg.GetCommandInt();
3991 int numCols = msg.GetCommandInt2();
f85afd4e 3992 m_numCols -= numCols;
f85afd4e 3993
f6bcfd97 3994 if ( !m_colWidths.IsEmpty() )
f85afd4e 3995 {
f6bcfd97
BP
3996 for ( i = 0; i < numCols; i++ )
3997 {
3998 m_colWidths.Remove( pos );
3999 m_colRights.Remove( pos );
4000 }
2d66e025
MB
4001
4002 int w = 0;
4003 for ( i = 0; i < m_numCols; i++ )
4004 {
4005 w += m_colWidths[i];
4006 m_colRights[i] = w;
4007 }
f85afd4e 4008 }
f6bcfd97
BP
4009 if ( !m_numCols )
4010 {
4011 m_currentCellCoords = wxGridNoCellCoords;
4012 }
4013 else
4014 {
4015 if ( m_currentCellCoords.GetCol() >= m_numCols )
4016 m_currentCellCoords.Set( 0, 0 );
4017 }
4018 m_selection->UpdateCols( pos, -((int)numCols) );
4019 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
4020 if (attrProvider) {
4021 attrProvider->UpdateAttrCols( pos, -((int)numCols) );
84912ef8
RD
4022// ifdef'd out following patch from Paul Gammans
4023#if 0
f6bcfd97
BP
4024 // No need to touch row attributes, unless we
4025 // removed _all_ columns, in this case, we remove
4026 // all row attributes.
4027 // I hate to do this here, but the
4028 // needed data is not available inside UpdateAttrCols.
4029 if ( !GetNumberCols() )
4030 attrProvider->UpdateAttrRows( 0, -GetNumberRows() );
84912ef8 4031#endif
f6bcfd97
BP
4032 }
4033 if ( !GetBatchCount() )
4034 {
4035 CalcDimensions();
4036 m_colLabelWin->Refresh();
4037 }
f85afd4e 4038 }
faec5a43 4039 result = TRUE;
f6bcfd97 4040 break;
f85afd4e
MB
4041 }
4042
f6bcfd97
BP
4043 if (result && !GetBatchCount() )
4044 m_gridWin->Refresh();
4045 return result;
f85afd4e
MB
4046}
4047
4048
f6bcfd97 4049void wxGrid::CalcRowLabelsExposed( const wxRegion& reg )
f85afd4e 4050{
2d66e025
MB
4051 wxRegionIterator iter( reg );
4052 wxRect r;
f85afd4e 4053
2d66e025 4054 m_rowLabelsExposed.Empty();
f85afd4e 4055
2d66e025
MB
4056 int top, bottom;
4057 while ( iter )
f85afd4e 4058 {
2d66e025 4059 r = iter.GetRect();
f85afd4e 4060
2d66e025
MB
4061 // TODO: remove this when we can...
4062 // There is a bug in wxMotif that gives garbage update
4063 // rectangles if you jump-scroll a long way by clicking the
4064 // scrollbar with middle button. This is a work-around
4065 //
4066#if defined(__WXMOTIF__)
4067 int cw, ch;
4068 m_gridWin->GetClientSize( &cw, &ch );
4069 if ( r.GetTop() > ch ) r.SetTop( 0 );
4070 r.SetBottom( wxMin( r.GetBottom(), ch ) );
4071#endif
f85afd4e 4072
2d66e025
MB
4073 // logical bounds of update region
4074 //
4075 int dummy;
4076 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
4077 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
4078
4079 // find the row labels within these bounds
4080 //
4081 int row;
2d66e025
MB
4082 for ( row = 0; row < m_numRows; row++ )
4083 {
7c1cb261
VZ
4084 if ( GetRowBottom(row) < top )
4085 continue;
2d66e025 4086
6d55126d 4087 if ( GetRowTop(row) > bottom )
7c1cb261 4088 break;
60ff3b99 4089
2d66e025
MB
4090 m_rowLabelsExposed.Add( row );
4091 }
60ff3b99 4092
2d66e025 4093 iter++ ;
f85afd4e
MB
4094 }
4095}
4096
4097
f6bcfd97 4098void wxGrid::CalcColLabelsExposed( const wxRegion& reg )
f85afd4e 4099{
2d66e025
MB
4100 wxRegionIterator iter( reg );
4101 wxRect r;
f85afd4e 4102
2d66e025 4103 m_colLabelsExposed.Empty();
f85afd4e 4104
2d66e025
MB
4105 int left, right;
4106 while ( iter )
f85afd4e 4107 {
2d66e025 4108 r = iter.GetRect();
f85afd4e 4109
2d66e025
MB
4110 // TODO: remove this when we can...
4111 // There is a bug in wxMotif that gives garbage update
4112 // rectangles if you jump-scroll a long way by clicking the
4113 // scrollbar with middle button. This is a work-around
4114 //
4115#if defined(__WXMOTIF__)
4116 int cw, ch;
4117 m_gridWin->GetClientSize( &cw, &ch );
4118 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
4119 r.SetRight( wxMin( r.GetRight(), cw ) );
4120#endif
4121
4122 // logical bounds of update region
4123 //
4124 int dummy;
4125 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
4126 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
4127
4128 // find the cells within these bounds
4129 //
4130 int col;
2d66e025
MB
4131 for ( col = 0; col < m_numCols; col++ )
4132 {
7c1cb261
VZ
4133 if ( GetColRight(col) < left )
4134 continue;
60ff3b99 4135
7c1cb261
VZ
4136 if ( GetColLeft(col) > right )
4137 break;
2d66e025
MB
4138
4139 m_colLabelsExposed.Add( col );
4140 }
60ff3b99 4141
2d66e025 4142 iter++ ;
f85afd4e
MB
4143 }
4144}
4145
4146
f6bcfd97 4147void wxGrid::CalcCellsExposed( const wxRegion& reg )
f85afd4e 4148{
2d66e025
MB
4149 wxRegionIterator iter( reg );
4150 wxRect r;
f85afd4e 4151
2d66e025
MB
4152 m_cellsExposed.Empty();
4153 m_rowsExposed.Empty();
4154 m_colsExposed.Empty();
f85afd4e 4155
2d66e025
MB
4156 int left, top, right, bottom;
4157 while ( iter )
4158 {
4159 r = iter.GetRect();
f85afd4e 4160
2d66e025
MB
4161 // TODO: remove this when we can...
4162 // There is a bug in wxMotif that gives garbage update
4163 // rectangles if you jump-scroll a long way by clicking the
4164 // scrollbar with middle button. This is a work-around
4165 //
4166#if defined(__WXMOTIF__)
f85afd4e 4167 int cw, ch;
2d66e025
MB
4168 m_gridWin->GetClientSize( &cw, &ch );
4169 if ( r.GetTop() > ch ) r.SetTop( 0 );
4170 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
4171 r.SetRight( wxMin( r.GetRight(), cw ) );
4172 r.SetBottom( wxMin( r.GetBottom(), ch ) );
4173#endif
8f177c8e 4174
2d66e025
MB
4175 // logical bounds of update region
4176 //
4177 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4178 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
f85afd4e 4179
2d66e025 4180 // find the cells within these bounds
f85afd4e 4181 //
2d66e025 4182 int row, col;
2d66e025 4183 for ( row = 0; row < m_numRows; row++ )
f85afd4e 4184 {
7c1cb261
VZ
4185 if ( GetRowBottom(row) <= top )
4186 continue;
f85afd4e 4187
7c1cb261
VZ
4188 if ( GetRowTop(row) > bottom )
4189 break;
60ff3b99 4190
2d66e025 4191 m_rowsExposed.Add( row );
f85afd4e 4192
2d66e025
MB
4193 for ( col = 0; col < m_numCols; col++ )
4194 {
7c1cb261
VZ
4195 if ( GetColRight(col) <= left )
4196 continue;
60ff3b99 4197
7c1cb261
VZ
4198 if ( GetColLeft(col) > right )
4199 break;
60ff3b99 4200
7c1cb261
VZ
4201 if ( m_colsExposed.Index( col ) == wxNOT_FOUND )
4202 m_colsExposed.Add( col );
2d66e025
MB
4203 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
4204 }
4205 }
60ff3b99 4206
7c1cb261 4207 iter++;
f85afd4e
MB
4208 }
4209}
4210
4211
2d66e025 4212void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
f85afd4e 4213{
2d66e025
MB
4214 int x, y, row;
4215 wxPoint pos( event.GetPosition() );
4216 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 4217
2d66e025 4218 if ( event.Dragging() )
f85afd4e
MB
4219 {
4220 m_isDragging = TRUE;
8f177c8e 4221
2d66e025 4222 if ( event.LeftIsDown() )
f85afd4e
MB
4223 {
4224 switch( m_cursorMode )
4225 {
f85afd4e
MB
4226 case WXGRID_CURSOR_RESIZE_ROW:
4227 {
2d66e025
MB
4228 int cw, ch, left, dummy;
4229 m_gridWin->GetClientSize( &cw, &ch );
4230 CalcUnscrolledPosition( 0, 0, &left, &dummy );
60ff3b99 4231
2d66e025
MB
4232 wxClientDC dc( m_gridWin );
4233 PrepareDC( dc );
af547d51
VZ
4234 y = wxMax( y,
4235 GetRowTop(m_dragRowOrCol) +
4236 GetRowMinimalHeight(m_dragRowOrCol) );
d2fdd8d2 4237 dc.SetLogicalFunction(wxINVERT);
f85afd4e
MB
4238 if ( m_dragLastPos >= 0 )
4239 {
2d66e025 4240 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
f85afd4e 4241 }
2d66e025
MB
4242 dc.DrawLine( left, y, left+cw, y );
4243 m_dragLastPos = y;
f85afd4e
MB
4244 }
4245 break;
4246
4247 case WXGRID_CURSOR_SELECT_ROW:
e32352cf 4248 if ( (row = YToRow( y )) >= 0 )
aa5e1f75
SN
4249 {
4250 m_selection->SelectRow( row,
4251 event.ControlDown(),
4252 event.ShiftDown(),
4253 event.AltDown(),
4254 event.MetaDown() );
f85afd4e 4255 }
e2b42eeb
VZ
4256
4257 // default label to suppress warnings about "enumeration value
4258 // 'xxx' not handled in switch
4259 default:
4260 break;
f85afd4e
MB
4261 }
4262 }
4263 return;
4264 }
4265
4266 m_isDragging = FALSE;
8f177c8e 4267
60ff3b99 4268
6d004f67
MB
4269 // ------------ Entering or leaving the window
4270 //
4271 if ( event.Entering() || event.Leaving() )
4272 {
e2b42eeb 4273 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
6d004f67
MB
4274 }
4275
e2b42eeb 4276
2d66e025 4277 // ------------ Left button pressed
f85afd4e 4278 //
6d004f67 4279 else if ( event.LeftDown() )
f85afd4e 4280 {
2d66e025
MB
4281 // don't send a label click event for a hit on the
4282 // edge of the row label - this is probably the user
4283 // wanting to resize the row
4284 //
4285 if ( YToEdgeOfRow(y) < 0 )
f85afd4e 4286 {
2d66e025 4287 row = YToRow(y);
58dd5b3b 4288 if ( row >= 0 &&
b54ba671 4289 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
f85afd4e 4290 {
aa5e1f75
SN
4291 if ( !event.ShiftDown() && !event.ControlDown() )
4292 ClearSelection();
4293 if ( event.ShiftDown() )
4294 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
4295 0,
4296 row,
4297 GetNumberCols() - 1,
4298 event.ControlDown(),
4299 event.ShiftDown(),
4300 event.AltDown(),
4301 event.MetaDown() );
4302 else
4303 m_selection->SelectRow( row,
4304 event.ControlDown(),
4305 event.ShiftDown(),
4306 event.AltDown(),
4307 event.MetaDown() );
e2b42eeb 4308 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
f85afd4e 4309 }
2d66e025
MB
4310 }
4311 else
4312 {
4313 // starting to drag-resize a row
4314 //
6e8524b1
MB
4315 if ( CanDragRowSize() )
4316 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
2d66e025
MB
4317 }
4318 }
f85afd4e 4319
f85afd4e 4320
2d66e025
MB
4321 // ------------ Left double click
4322 //
4323 else if (event.LeftDClick() )
4324 {
4325 if ( YToEdgeOfRow(y) < 0 )
4326 {
4327 row = YToRow(y);
b54ba671 4328 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
f85afd4e
MB
4329 }
4330 }
60ff3b99
VZ
4331
4332
2d66e025 4333 // ------------ Left button released
f85afd4e 4334 //
2d66e025 4335 else if ( event.LeftUp() )
f85afd4e 4336 {
2d66e025 4337 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
f85afd4e 4338 {
6d004f67 4339 DoEndDragResizeRow();
60ff3b99 4340
6d004f67
MB
4341 // Note: we are ending the event *after* doing
4342 // default processing in this case
4343 //
b54ba671 4344 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
2d66e025 4345 }
f85afd4e 4346
e2b42eeb
VZ
4347 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
4348 m_dragLastPos = -1;
2d66e025 4349 }
f85afd4e 4350
f85afd4e 4351
2d66e025
MB
4352 // ------------ Right button down
4353 //
4354 else if ( event.RightDown() )
4355 {
4356 row = YToRow(y);
b54ba671 4357 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
2d66e025
MB
4358 {
4359 // no default action at the moment
f85afd4e
MB
4360 }
4361 }
60ff3b99
VZ
4362
4363
2d66e025 4364 // ------------ Right double click
f85afd4e 4365 //
2d66e025
MB
4366 else if ( event.RightDClick() )
4367 {
4368 row = YToRow(y);
b54ba671 4369 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
2d66e025
MB
4370 {
4371 // no default action at the moment
4372 }
4373 }
60ff3b99
VZ
4374
4375
2d66e025 4376 // ------------ No buttons down and mouse moving
f85afd4e 4377 //
2d66e025 4378 else if ( event.Moving() )
f85afd4e 4379 {
2d66e025
MB
4380 m_dragRowOrCol = YToEdgeOfRow( y );
4381 if ( m_dragRowOrCol >= 0 )
8f177c8e 4382 {
2d66e025 4383 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
8f177c8e 4384 {
e2b42eeb 4385 // don't capture the mouse yet
6e8524b1
MB
4386 if ( CanDragRowSize() )
4387 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
8f177c8e 4388 }
2d66e025 4389 }
6d004f67 4390 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2d66e025 4391 {
e2b42eeb 4392 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
8f177c8e 4393 }
f85afd4e 4394 }
2d66e025
MB
4395}
4396
4397
4398void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
4399{
4400 int x, y, col;
4401 wxPoint pos( event.GetPosition() );
4402 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 4403
2d66e025 4404 if ( event.Dragging() )
f85afd4e 4405 {
2d66e025 4406 m_isDragging = TRUE;
8f177c8e 4407
2d66e025 4408 if ( event.LeftIsDown() )
8f177c8e 4409 {
2d66e025 4410 switch( m_cursorMode )
8f177c8e 4411 {
2d66e025 4412 case WXGRID_CURSOR_RESIZE_COL:
8f177c8e 4413 {
2d66e025
MB
4414 int cw, ch, dummy, top;
4415 m_gridWin->GetClientSize( &cw, &ch );
4416 CalcUnscrolledPosition( 0, 0, &dummy, &top );
60ff3b99 4417
2d66e025
MB
4418 wxClientDC dc( m_gridWin );
4419 PrepareDC( dc );
43947979
VZ
4420
4421 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
4422 GetColMinimalWidth(m_dragRowOrCol));
d2fdd8d2 4423 dc.SetLogicalFunction(wxINVERT);
2d66e025
MB
4424 if ( m_dragLastPos >= 0 )
4425 {
4426 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
4427 }
4428 dc.DrawLine( x, top, x, top+ch );
4429 m_dragLastPos = x;
f85afd4e 4430 }
2d66e025 4431 break;
f85afd4e 4432
2d66e025 4433 case WXGRID_CURSOR_SELECT_COL:
e32352cf 4434 if ( (col = XToCol( x )) >= 0 )
aa5e1f75
SN
4435 {
4436 m_selection->SelectCol( col,
4437 event.ControlDown(),
4438 event.ShiftDown(),
4439 event.AltDown(),
4440 event.MetaDown() );
2d66e025 4441 }
e2b42eeb
VZ
4442
4443 // default label to suppress warnings about "enumeration value
4444 // 'xxx' not handled in switch
4445 default:
4446 break;
2d66e025 4447 }
f85afd4e 4448 }
2d66e025 4449 return;
f85afd4e 4450 }
2d66e025
MB
4451
4452 m_isDragging = FALSE;
4453
60ff3b99 4454
6d004f67
MB
4455 // ------------ Entering or leaving the window
4456 //
4457 if ( event.Entering() || event.Leaving() )
4458 {
e2b42eeb 4459 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
6d004f67
MB
4460 }
4461
e2b42eeb 4462
2d66e025 4463 // ------------ Left button pressed
f85afd4e 4464 //
6d004f67 4465 else if ( event.LeftDown() )
f85afd4e 4466 {
2d66e025
MB
4467 // don't send a label click event for a hit on the
4468 // edge of the col label - this is probably the user
4469 // wanting to resize the col
4470 //
4471 if ( XToEdgeOfCol(x) < 0 )
8f177c8e 4472 {
2d66e025 4473 col = XToCol(x);
58dd5b3b 4474 if ( col >= 0 &&
b54ba671 4475 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
8f177c8e 4476 {
aa5e1f75
SN
4477 if ( !event.ShiftDown() && !event.ControlDown() )
4478 ClearSelection();
4479 if ( event.ShiftDown() )
4480 m_selection->SelectBlock( 0,
4481 m_currentCellCoords.GetCol(),
4482 GetNumberRows() - 1, col,
4483 event.ControlDown(),
4484 event.ShiftDown(),
4485 event.AltDown(),
4486 event.MetaDown() );
4487 else
4488 m_selection->SelectCol( col,
4489 event.ControlDown(),
4490 event.ShiftDown(),
4491 event.AltDown(),
4492 event.MetaDown() );
e2b42eeb 4493 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
f85afd4e 4494 }
2d66e025
MB
4495 }
4496 else
4497 {
4498 // starting to drag-resize a col
4499 //
6e8524b1
MB
4500 if ( CanDragColSize() )
4501 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
2d66e025
MB
4502 }
4503 }
f85afd4e 4504
f85afd4e 4505
2d66e025
MB
4506 // ------------ Left double click
4507 //
4508 if ( event.LeftDClick() )
4509 {
4510 if ( XToEdgeOfCol(x) < 0 )
4511 {
4512 col = XToCol(x);
b54ba671 4513 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
2d66e025
MB
4514 }
4515 }
60ff3b99
VZ
4516
4517
2d66e025
MB
4518 // ------------ Left button released
4519 //
4520 else if ( event.LeftUp() )
4521 {
4522 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4523 {
6d004f67 4524 DoEndDragResizeCol();
e2b42eeb 4525
6d004f67
MB
4526 // Note: we are ending the event *after* doing
4527 // default processing in this case
4528 //
b54ba671 4529 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2d66e025 4530 }
f85afd4e 4531
e2b42eeb 4532 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
2d66e025 4533 m_dragLastPos = -1;
60ff3b99
VZ
4534 }
4535
4536
2d66e025
MB
4537 // ------------ Right button down
4538 //
4539 else if ( event.RightDown() )
4540 {
4541 col = XToCol(x);
b54ba671 4542 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
2d66e025
MB
4543 {
4544 // no default action at the moment
f85afd4e
MB
4545 }
4546 }
60ff3b99
VZ
4547
4548
2d66e025 4549 // ------------ Right double click
f85afd4e 4550 //
2d66e025
MB
4551 else if ( event.RightDClick() )
4552 {
4553 col = XToCol(x);
b54ba671 4554 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
2d66e025
MB
4555 {
4556 // no default action at the moment
4557 }
4558 }
60ff3b99
VZ
4559
4560
2d66e025 4561 // ------------ No buttons down and mouse moving
f85afd4e 4562 //
2d66e025 4563 else if ( event.Moving() )
f85afd4e 4564 {
2d66e025
MB
4565 m_dragRowOrCol = XToEdgeOfCol( x );
4566 if ( m_dragRowOrCol >= 0 )
f85afd4e 4567 {
2d66e025 4568 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
f85afd4e 4569 {
e2b42eeb 4570 // don't capture the cursor yet
6e8524b1
MB
4571 if ( CanDragColSize() )
4572 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
f85afd4e 4573 }
2d66e025 4574 }
6d004f67 4575 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2d66e025 4576 {
e2b42eeb 4577 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
8f177c8e 4578 }
f85afd4e
MB
4579 }
4580}
4581
4582
2d66e025 4583void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
f85afd4e 4584{
2d66e025 4585 if ( event.LeftDown() )
f85afd4e 4586 {
2d66e025
MB
4587 // indicate corner label by having both row and
4588 // col args == -1
f85afd4e 4589 //
b54ba671 4590 if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
2d66e025
MB
4591 {
4592 SelectAll();
4593 }
f85afd4e
MB
4594 }
4595
2d66e025
MB
4596 else if ( event.LeftDClick() )
4597 {
b54ba671 4598 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
2d66e025 4599 }
8f177c8e 4600
2d66e025 4601 else if ( event.RightDown() )
f85afd4e 4602 {
b54ba671 4603 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
f85afd4e 4604 {
2d66e025
MB
4605 // no default action at the moment
4606 }
4607 }
f85afd4e 4608
2d66e025
MB
4609 else if ( event.RightDClick() )
4610 {
b54ba671 4611 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
2d66e025
MB
4612 {
4613 // no default action at the moment
4614 }
4615 }
4616}
f85afd4e 4617
e2b42eeb
VZ
4618void wxGrid::ChangeCursorMode(CursorMode mode,
4619 wxWindow *win,
4620 bool captureMouse)
4621{
4622#ifdef __WXDEBUG__
4623 static const wxChar *cursorModes[] =
4624 {
4625 _T("SELECT_CELL"),
4626 _T("RESIZE_ROW"),
4627 _T("RESIZE_COL"),
4628 _T("SELECT_ROW"),
4629 _T("SELECT_COL")
4630 };
4631
181bfffd
VZ
4632 wxLogTrace(_T("grid"),
4633 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
e2b42eeb
VZ
4634 win == m_colLabelWin ? _T("colLabelWin")
4635 : win ? _T("rowLabelWin")
4636 : _T("gridWin"),
4637 cursorModes[m_cursorMode], cursorModes[mode]);
4638#endif // __WXDEBUG__
4639
faec5a43
SN
4640 if ( mode == m_cursorMode &&
4641 win == m_winCapture &&
4642 captureMouse == (m_winCapture != NULL))
e2b42eeb
VZ
4643 return;
4644
4645 if ( !win )
4646 {
4647 // by default use the grid itself
4648 win = m_gridWin;
4649 }
4650
4651 if ( m_winCapture )
4652 {
4653 m_winCapture->ReleaseMouse();
4654 m_winCapture = (wxWindow *)NULL;
4655 }
4656
4657 m_cursorMode = mode;
4658
4659 switch ( m_cursorMode )
4660 {
4661 case WXGRID_CURSOR_RESIZE_ROW:
4662 win->SetCursor( m_rowResizeCursor );
4663 break;
4664
4665 case WXGRID_CURSOR_RESIZE_COL:
4666 win->SetCursor( m_colResizeCursor );
4667 break;
4668
4669 default:
4670 win->SetCursor( *wxSTANDARD_CURSOR );
4671 }
4672
4673 // we need to capture mouse when resizing
4674 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
4675 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
4676
4677 if ( captureMouse && resize )
4678 {
4679 win->CaptureMouse();
4680 m_winCapture = win;
4681 }
4682}
8f177c8e 4683
2d66e025
MB
4684void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
4685{
4686 int x, y;
4687 wxPoint pos( event.GetPosition() );
4688 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 4689
2d66e025
MB
4690 wxGridCellCoords coords;
4691 XYToCell( x, y, coords );
60ff3b99 4692
2d66e025
MB
4693 if ( event.Dragging() )
4694 {
07296f0b
RD
4695 //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
4696
4697 // Don't start doing anything until the mouse has been drug at
4698 // least 3 pixels in any direction...
508011ce
VZ
4699 if (! m_isDragging)
4700 {
4701 if (m_startDragPos == wxDefaultPosition)
4702 {
07296f0b
RD
4703 m_startDragPos = pos;
4704 return;
4705 }
4706 if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
4707 return;
4708 }
4709
2d66e025 4710 m_isDragging = TRUE;
2d66e025
MB
4711 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4712 {
f0102d2a
VZ
4713 // Hide the edit control, so it
4714 // won't interfer with drag-shrinking.
f6bcfd97 4715 if ( IsCellEditControlShown() )
a5777624 4716 {
f0102d2a 4717 HideCellEditControl();
a5777624
RD
4718 SaveEditControlValue();
4719 }
07296f0b
RD
4720
4721 // Have we captured the mouse yet?
508011ce
VZ
4722 if (! m_winCapture)
4723 {
07296f0b
RD
4724 m_winCapture = m_gridWin;
4725 m_winCapture->CaptureMouse();
4726 }
4727
2d66e025
MB
4728 if ( coords != wxGridNoCellCoords )
4729 {
aa5e1f75
SN
4730 if ( event.ControlDown() )
4731 {
4732 if ( m_selectingKeyboard == wxGridNoCellCoords)
4733 m_selectingKeyboard = coords;
c9097836 4734 HighlightBlock ( m_selectingKeyboard, coords );
aa5e1f75
SN
4735 }
4736 else
4737 {
4738 if ( !IsSelection() )
4739 {
c9097836 4740 HighlightBlock( coords, coords );
aa5e1f75
SN
4741 }
4742 else
4743 {
c9097836 4744 HighlightBlock( m_currentCellCoords, coords );
aa5e1f75 4745 }
f85afd4e 4746 }
07296f0b 4747
508011ce
VZ
4748 if (! IsVisible(coords))
4749 {
07296f0b
RD
4750 MakeCellVisible(coords);
4751 // TODO: need to introduce a delay or something here. The
e32352cf 4752 // scrolling is way to fast, at least on MSW - also on GTK.
07296f0b 4753 }
2d66e025
MB
4754 }
4755 }
6d004f67
MB
4756 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4757 {
4758 int cw, ch, left, dummy;
4759 m_gridWin->GetClientSize( &cw, &ch );
4760 CalcUnscrolledPosition( 0, 0, &left, &dummy );
8f177c8e 4761
6d004f67
MB
4762 wxClientDC dc( m_gridWin );
4763 PrepareDC( dc );
a95e38c0
VZ
4764 y = wxMax( y, GetRowTop(m_dragRowOrCol) +
4765 GetRowMinimalHeight(m_dragRowOrCol) );
6d004f67
MB
4766 dc.SetLogicalFunction(wxINVERT);
4767 if ( m_dragLastPos >= 0 )
4768 {
4769 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
4770 }
4771 dc.DrawLine( left, y, left+cw, y );
4772 m_dragLastPos = y;
4773 }
4774 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4775 {
4776 int cw, ch, dummy, top;
4777 m_gridWin->GetClientSize( &cw, &ch );
4778 CalcUnscrolledPosition( 0, 0, &dummy, &top );
e2b42eeb 4779
6d004f67
MB
4780 wxClientDC dc( m_gridWin );
4781 PrepareDC( dc );
43947979
VZ
4782 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
4783 GetColMinimalWidth(m_dragRowOrCol) );
6d004f67
MB
4784 dc.SetLogicalFunction(wxINVERT);
4785 if ( m_dragLastPos >= 0 )
4786 {
4787 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
4788 }
4789 dc.DrawLine( x, top, x, top+ch );
4790 m_dragLastPos = x;
4791 }
e2b42eeb 4792
2d66e025
MB
4793 return;
4794 }
66242c80 4795
2d66e025 4796 m_isDragging = FALSE;
07296f0b
RD
4797 m_startDragPos = wxDefaultPosition;
4798
a5777624
RD
4799 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
4800 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
4801 // wxGTK
e2b42eeb 4802#if 0
a5777624
RD
4803 if ( event.Entering() || event.Leaving() )
4804 {
4805 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4806 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
4807 }
4808 else
e2b42eeb
VZ
4809#endif // 0
4810
a5777624
RD
4811 // ------------ Left button pressed
4812 //
4813 if ( event.LeftDown() && coords != wxGridNoCellCoords )
f6bcfd97
BP
4814 {
4815 if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK,
4816 coords.GetRow(),
4817 coords.GetCol(),
4818 event ) )
a5777624 4819 {
f6bcfd97
BP
4820 if ( !event.ControlDown() )
4821 ClearSelection();
4822 if ( event.ShiftDown() )
4823 {
4824 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
4825 m_currentCellCoords.GetCol(),
4826 coords.GetRow(),
4827 coords.GetCol(),
4828 event.ControlDown(),
4829 event.ShiftDown(),
4830 event.AltDown(),
4831 event.MetaDown() );
4832 }
4833 else if ( XToEdgeOfCol(x) < 0 &&
4834 YToEdgeOfRow(y) < 0 )
58dd5b3b 4835 {
a5777624
RD
4836 DisableCellEditControl();
4837 MakeCellVisible( coords );
4838
4839 // if this is the second click on this cell then start
4840 // the edit control
4841 if ( m_waitForSlowClick &&
4842 (coords == m_currentCellCoords) &&
4843 CanEnableCellControl())
58dd5b3b 4844 {
a5777624 4845 EnableCellEditControl();
e195a54c 4846
a5777624 4847 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
0b190b0f
VZ
4848 wxGridCellEditor *editor = attr->GetEditor(this,
4849 coords.GetRow(),
4850 coords.GetCol());
4851 editor->StartingClick();
4852 editor->DecRef();
a5777624 4853 attr->DecRef();
e195a54c 4854
a5777624
RD
4855 m_waitForSlowClick = FALSE;
4856 }
4857 else
4858 {
aa5e1f75
SN
4859 if ( event.ControlDown() )
4860 {
4861 m_selection->ToggleCellSelection( coords.GetRow(),
4862 coords.GetCol(),
4863 event.ControlDown(),
4864 event.ShiftDown(),
4865 event.AltDown(),
4866 event.MetaDown() );
4867 m_selectingTopLeft = wxGridNoCellCoords;
4868 m_selectingBottomRight = wxGridNoCellCoords;
4869 m_selectingKeyboard = coords;
4870 }
4871 else
f6bcfd97 4872 {
aa5e1f75 4873 SetCurrentCell( coords );
f6bcfd97
BP
4874 if ( m_selection->GetSelectionMode()
4875 != wxGrid::wxGridSelectCells)
c9097836 4876 HighlightBlock( coords, coords );
f6bcfd97 4877 }
a5777624 4878 m_waitForSlowClick = TRUE;
58dd5b3b
MB
4879 }
4880 }
f85afd4e 4881 }
a5777624 4882 }
f85afd4e 4883
f85afd4e 4884
a5777624
RD
4885 // ------------ Left double click
4886 //
4887 else if ( event.LeftDClick() && coords != wxGridNoCellCoords )
4888 {
4889 DisableCellEditControl();
4890
4891 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
58dd5b3b 4892 {
a5777624
RD
4893 SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK,
4894 coords.GetRow(),
4895 coords.GetCol(),
4896 event );
58dd5b3b 4897 }
a5777624 4898 }
f85afd4e 4899
8f177c8e 4900
a5777624
RD
4901 // ------------ Left button released
4902 //
4903 else if ( event.LeftUp() )
4904 {
4905 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
f85afd4e 4906 {
b5808881
SN
4907 if ( m_selectingTopLeft != wxGridNoCellCoords &&
4908 m_selectingBottomRight != wxGridNoCellCoords )
52068ea5 4909 {
a5777624 4910 if (m_winCapture)
58dd5b3b 4911 {
a5777624
RD
4912 m_winCapture->ReleaseMouse();
4913 m_winCapture = NULL;
58dd5b3b 4914 }
5c8fc7c1
SN
4915 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
4916 m_selectingTopLeft.GetCol(),
4917 m_selectingBottomRight.GetRow(),
4918 m_selectingBottomRight.GetCol(),
d95b0c2b
SN
4919 event.ControlDown(),
4920 event.ShiftDown(),
4921 event.AltDown(),
4922 event.MetaDown() );
5c8fc7c1
SN
4923 m_selectingTopLeft = wxGridNoCellCoords;
4924 m_selectingBottomRight = wxGridNoCellCoords;
6d004f67 4925 }
2d66e025 4926
a5777624
RD
4927 // Show the edit control, if it has been hidden for
4928 // drag-shrinking.
4929 ShowCellEditControl();
4930 }
4931 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4932 {
4933 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4934 DoEndDragResizeRow();
e2b42eeb 4935
a5777624
RD
4936 // Note: we are ending the event *after* doing
4937 // default processing in this case
4938 //
4939 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
4940 }
4941 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4942 {
4943 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4944 DoEndDragResizeCol();
e2b42eeb 4945
a5777624
RD
4946 // Note: we are ending the event *after* doing
4947 // default processing in this case
4948 //
4949 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
58dd5b3b 4950 }
f85afd4e 4951
a5777624
RD
4952 m_dragLastPos = -1;
4953 }
4954
f85afd4e 4955
a5777624
RD
4956 // ------------ Right button down
4957 //
4958 else if ( event.RightDown() && coords != wxGridNoCellCoords )
4959 {
4960 DisableCellEditControl();
4961 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK,
4962 coords.GetRow(),
4963 coords.GetCol(),
4964 event ) )
f85afd4e 4965 {
a5777624 4966 // no default action at the moment
60ff3b99 4967 }
a5777624 4968 }
2d66e025 4969
60ff3b99 4970
a5777624
RD
4971 // ------------ Right double click
4972 //
4973 else if ( event.RightDClick() && coords != wxGridNoCellCoords )
4974 {
4975 DisableCellEditControl();
4976 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK,
4977 coords.GetRow(),
4978 coords.GetCol(),
4979 event ) )
f85afd4e 4980 {
a5777624 4981 // no default action at the moment
60ff3b99 4982 }
a5777624
RD
4983 }
4984
4985 // ------------ Moving and no button action
4986 //
4987 else if ( event.Moving() && !event.IsButton() )
4988 {
4989 int dragRow = YToEdgeOfRow( y );
4990 int dragCol = XToEdgeOfCol( x );
790cc417 4991
a5777624
RD
4992 // Dragging on the corner of a cell to resize in both
4993 // directions is not implemented yet...
790cc417 4994 //
a5777624 4995 if ( dragRow >= 0 && dragCol >= 0 )
790cc417 4996 {
a5777624
RD
4997 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4998 return;
4999 }
6d004f67 5000
a5777624
RD
5001 if ( dragRow >= 0 )
5002 {
5003 m_dragRowOrCol = dragRow;
6d004f67 5004
a5777624 5005 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
6d004f67 5006 {
a5777624
RD
5007 if ( CanDragRowSize() && CanDragGridSize() )
5008 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
6d004f67 5009 }
e2b42eeb 5010
b94ae1ea
VZ
5011 if ( dragCol >= 0 )
5012 {
5013 m_dragRowOrCol = dragCol;
122603f1 5014 }
b94ae1ea 5015
a5777624
RD
5016 return;
5017 }
e2b42eeb 5018
a5777624
RD
5019 if ( dragCol >= 0 )
5020 {
5021 m_dragRowOrCol = dragCol;
e2b42eeb 5022
a5777624 5023 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
6d004f67 5024 {
a5777624
RD
5025 if ( CanDragColSize() && CanDragGridSize() )
5026 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
6d004f67 5027 }
a5777624
RD
5028
5029 return;
6d004f67 5030 }
a5777624
RD
5031
5032 // Neither on a row or col edge
5033 //
5034 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
5035 {
5036 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
5037 }
5038 }
6d004f67
MB
5039}
5040
5041
5042void wxGrid::DoEndDragResizeRow()
5043{
5044 if ( m_dragLastPos >= 0 )
5045 {
5046 // erase the last line and resize the row
5047 //
5048 int cw, ch, left, dummy;
5049 m_gridWin->GetClientSize( &cw, &ch );
5050 CalcUnscrolledPosition( 0, 0, &left, &dummy );
5051
5052 wxClientDC dc( m_gridWin );
5053 PrepareDC( dc );
5054 dc.SetLogicalFunction( wxINVERT );
5055 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
5056 HideCellEditControl();
a5777624 5057 SaveEditControlValue();
6d004f67 5058
7c1cb261 5059 int rowTop = GetRowTop(m_dragRowOrCol);
6d004f67
MB
5060 SetRowSize( m_dragRowOrCol,
5061 wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
e2b42eeb 5062
6d004f67
MB
5063 if ( !GetBatchCount() )
5064 {
5065 // Only needed to get the correct rect.y:
5066 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
5067 rect.x = 0;
5068 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
5069 rect.width = m_rowLabelWidth;
5070 rect.height = ch - rect.y;
5071 m_rowLabelWin->Refresh( TRUE, &rect );
5072 rect.width = cw;
5073 m_gridWin->Refresh( FALSE, &rect );
5074 }
5075
5076 ShowCellEditControl();
5077 }
5078}
5079
5080
5081void wxGrid::DoEndDragResizeCol()
5082{
5083 if ( m_dragLastPos >= 0 )
5084 {
5085 // erase the last line and resize the col
5086 //
5087 int cw, ch, dummy, top;
5088 m_gridWin->GetClientSize( &cw, &ch );
5089 CalcUnscrolledPosition( 0, 0, &dummy, &top );
5090
5091 wxClientDC dc( m_gridWin );
5092 PrepareDC( dc );
5093 dc.SetLogicalFunction( wxINVERT );
5094 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
5095 HideCellEditControl();
a5777624 5096 SaveEditControlValue();
6d004f67 5097
7c1cb261 5098 int colLeft = GetColLeft(m_dragRowOrCol);
6d004f67 5099 SetColSize( m_dragRowOrCol,
43947979
VZ
5100 wxMax( m_dragLastPos - colLeft,
5101 GetColMinimalWidth(m_dragRowOrCol) ) );
6d004f67
MB
5102
5103 if ( !GetBatchCount() )
5104 {
5105 // Only needed to get the correct rect.x:
5106 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
5107 rect.y = 0;
5108 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
5109 rect.width = cw - rect.x;
5110 rect.height = m_colLabelHeight;
5111 m_colLabelWin->Refresh( TRUE, &rect );
5112 rect.height = ch;
5113 m_gridWin->Refresh( FALSE, &rect );
790cc417 5114 }
e2b42eeb 5115
6d004f67 5116 ShowCellEditControl();
f85afd4e 5117 }
f85afd4e
MB
5118}
5119
5120
6d004f67 5121
2d66e025
MB
5122//
5123// ------ interaction with data model
5124//
5125bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
f85afd4e 5126{
2d66e025 5127 switch ( msg.GetId() )
17732cec 5128 {
2d66e025
MB
5129 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
5130 return GetModelValues();
17732cec 5131
2d66e025
MB
5132 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
5133 return SetModelValues();
f85afd4e 5134
2d66e025
MB
5135 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
5136 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
5137 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
5138 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
5139 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
5140 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
5141 return Redimension( msg );
5142
5143 default:
5144 return FALSE;
f85afd4e 5145 }
2d66e025 5146}
f85afd4e 5147
f85afd4e 5148
f85afd4e 5149
2d66e025
MB
5150// The behaviour of this function depends on the grid table class
5151// Clear() function. For the default wxGridStringTable class the
5152// behavious is to replace all cell contents with wxEmptyString but
5153// not to change the number of rows or cols.
5154//
5155void wxGrid::ClearGrid()
5156{
5157 if ( m_table )
f85afd4e 5158 {
4cfa5de6
RD
5159 if (IsCellEditControlEnabled())
5160 DisableCellEditControl();
5161
2d66e025 5162 m_table->Clear();
1f1ce288 5163 if ( !GetBatchCount() ) m_gridWin->Refresh();
f85afd4e
MB
5164 }
5165}
5166
5167
2d66e025 5168bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 5169{
2d66e025 5170 // TODO: something with updateLabels flag
8f177c8e 5171
2d66e025 5172 if ( !m_created )
f85afd4e 5173 {
bd3c6758 5174 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2d66e025
MB
5175 return FALSE;
5176 }
8f177c8e 5177
2d66e025
MB
5178 if ( m_table )
5179 {
b7fff980 5180 if (IsCellEditControlEnabled())
b54ba671 5181 DisableCellEditControl();
b7fff980 5182
f6bcfd97 5183 return m_table->InsertRows( pos, numRows );
f85afd4e 5184
2d66e025
MB
5185 // the table will have sent the results of the insert row
5186 // operation to this view object as a grid table message
f85afd4e 5187 }
f6bcfd97 5188 return FALSE;
f85afd4e
MB
5189}
5190
5191
2d66e025 5192bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 5193{
2d66e025
MB
5194 // TODO: something with updateLabels flag
5195
5196 if ( !m_created )
f85afd4e 5197 {
bd3c6758 5198 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2d66e025
MB
5199 return FALSE;
5200 }
5201
f6bcfd97
BP
5202 return ( m_table && m_table->AppendRows( numRows ) );
5203 // the table will have sent the results of the append row
5204 // operation to this view object as a grid table message
f85afd4e
MB
5205}
5206
2d66e025
MB
5207
5208bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 5209{
2d66e025
MB
5210 // TODO: something with updateLabels flag
5211
5212 if ( !m_created )
f85afd4e 5213 {
bd3c6758 5214 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2d66e025
MB
5215 return FALSE;
5216 }
5217
b7fff980 5218 if ( m_table )
2d66e025 5219 {
b7fff980 5220 if (IsCellEditControlEnabled())
b54ba671 5221 DisableCellEditControl();
f85afd4e 5222
f6bcfd97
BP
5223 return (m_table->DeleteRows( pos, numRows ));
5224 // the table will have sent the results of the delete row
5225 // operation to this view object as a grid table message
2d66e025 5226 }
b7fff980 5227 return FALSE;
2d66e025 5228}
f85afd4e 5229
f85afd4e 5230
2d66e025
MB
5231bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
5232{
5233 // TODO: something with updateLabels flag
8f177c8e 5234
2d66e025
MB
5235 if ( !m_created )
5236 {
bd3c6758 5237 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2d66e025
MB
5238 return FALSE;
5239 }
f85afd4e 5240
2d66e025
MB
5241 if ( m_table )
5242 {
b7fff980 5243 if (IsCellEditControlEnabled())
b54ba671 5244 DisableCellEditControl();
b7fff980 5245
f6bcfd97 5246 return m_table->InsertCols( pos, numCols );
2d66e025
MB
5247 // the table will have sent the results of the insert col
5248 // operation to this view object as a grid table message
f85afd4e 5249 }
f6bcfd97 5250 return FALSE;
f85afd4e
MB
5251}
5252
2d66e025
MB
5253
5254bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 5255{
2d66e025
MB
5256 // TODO: something with updateLabels flag
5257
5258 if ( !m_created )
f85afd4e 5259 {
bd3c6758 5260 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2d66e025
MB
5261 return FALSE;
5262 }
f85afd4e 5263
f6bcfd97
BP
5264 return ( m_table && m_table->AppendCols( numCols ) );
5265 // the table will have sent the results of the append col
5266 // operation to this view object as a grid table message
f85afd4e
MB
5267}
5268
5269
2d66e025 5270bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 5271{
2d66e025 5272 // TODO: something with updateLabels flag
8f177c8e 5273
2d66e025 5274 if ( !m_created )
f85afd4e 5275 {
bd3c6758 5276 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2d66e025 5277 return FALSE;
f85afd4e
MB
5278 }
5279
b7fff980 5280 if ( m_table )
2d66e025 5281 {
b7fff980 5282 if (IsCellEditControlEnabled())
b54ba671 5283 DisableCellEditControl();
8f177c8e 5284
f6bcfd97
BP
5285 return ( m_table->DeleteCols( pos, numCols ) );
5286 // the table will have sent the results of the delete col
5287 // operation to this view object as a grid table message
f85afd4e 5288 }
b7fff980 5289 return FALSE;
f85afd4e
MB
5290}
5291
5292
2d66e025
MB
5293
5294//
5295// ----- event handlers
f85afd4e 5296//
8f177c8e 5297
2d66e025
MB
5298// Generate a grid event based on a mouse event and
5299// return the result of ProcessEvent()
5300//
5301bool wxGrid::SendEvent( const wxEventType type,
5302 int row, int col,
5303 wxMouseEvent& mouseEv )
5304{
b54ba671 5305 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
f85afd4e 5306 {
2d66e025
MB
5307 int rowOrCol = (row == -1 ? col : row);
5308
5309 wxGridSizeEvent gridEvt( GetId(),
5310 type,
5311 this,
5312 rowOrCol,
faec5a43
SN
5313 mouseEv.GetX() + GetRowLabelSize(),
5314 mouseEv.GetY() + GetColLabelSize(),
2d66e025
MB
5315 mouseEv.ControlDown(),
5316 mouseEv.ShiftDown(),
5317 mouseEv.AltDown(),
5318 mouseEv.MetaDown() );
2d66e025 5319 return GetEventHandler()->ProcessEvent(gridEvt);
f85afd4e 5320 }
b54ba671 5321 else if ( type == wxEVT_GRID_RANGE_SELECT )
2d66e025 5322 {
f6bcfd97 5323 // Right now, it should _never_ end up here!
2d66e025
MB
5324 wxGridRangeSelectEvent gridEvt( GetId(),
5325 type,
5326 this,
b5808881
SN
5327 m_selectingTopLeft,
5328 m_selectingBottomRight,
5c8fc7c1 5329 TRUE,
2d66e025
MB
5330 mouseEv.ControlDown(),
5331 mouseEv.ShiftDown(),
5332 mouseEv.AltDown(),
5333 mouseEv.MetaDown() );
f85afd4e 5334
2d66e025
MB
5335 return GetEventHandler()->ProcessEvent(gridEvt);
5336 }
5337 else
5338 {
5339 wxGridEvent gridEvt( GetId(),
5340 type,
5341 this,
5342 row, col,
faec5a43
SN
5343 mouseEv.GetX() + GetRowLabelSize(),
5344 mouseEv.GetY() + GetColLabelSize(),
d7da9756 5345 FALSE,
2d66e025
MB
5346 mouseEv.ControlDown(),
5347 mouseEv.ShiftDown(),
5348 mouseEv.AltDown(),
5349 mouseEv.MetaDown() );
2d66e025
MB
5350 return GetEventHandler()->ProcessEvent(gridEvt);
5351 }
f85afd4e
MB
5352}
5353
5354
2d66e025
MB
5355// Generate a grid event of specified type and return the result
5356// of ProcessEvent().
f85afd4e 5357//
2d66e025
MB
5358bool wxGrid::SendEvent( const wxEventType type,
5359 int row, int col )
f85afd4e 5360{
b54ba671 5361 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
f85afd4e 5362 {
2d66e025 5363 int rowOrCol = (row == -1 ? col : row);
f85afd4e 5364
2d66e025
MB
5365 wxGridSizeEvent gridEvt( GetId(),
5366 type,
5367 this,
5368 rowOrCol );
5369
5370 return GetEventHandler()->ProcessEvent(gridEvt);
5371 }
5372 else
5373 {
5374 wxGridEvent gridEvt( GetId(),
5375 type,
5376 this,
5377 row, col );
8f177c8e 5378
2d66e025
MB
5379 return GetEventHandler()->ProcessEvent(gridEvt);
5380 }
f85afd4e
MB
5381}
5382
5383
2d66e025 5384void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
f85afd4e 5385{
f6bcfd97 5386 wxPaintDC dc(this); // needed to prevent zillions of paint events on MSW
8f177c8e 5387}
f85afd4e
MB
5388
5389
18f9565d
MB
5390// This is just here to make sure that CalcDimensions gets called when
5391// the grid view is resized... then the size event is skipped to allow
5392// the box sizers to handle everything
5393//
aa5e1f75 5394void wxGrid::OnSize( wxSizeEvent& WXUNUSED(event) )
f85afd4e 5395{
7807d81c 5396 CalcWindowSizes();
2d66e025 5397 CalcDimensions();
f85afd4e
MB
5398}
5399
f85afd4e 5400
2d66e025 5401void wxGrid::OnKeyDown( wxKeyEvent& event )
f85afd4e 5402{
2d66e025 5403 if ( m_inOnKeyDown )
f85afd4e 5404 {
2d66e025
MB
5405 // shouldn't be here - we are going round in circles...
5406 //
07296f0b 5407 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
f85afd4e
MB
5408 }
5409
2d66e025 5410 m_inOnKeyDown = TRUE;
f85afd4e 5411
2d66e025
MB
5412 // propagate the event up and see if it gets processed
5413 //
5414 wxWindow *parent = GetParent();
5415 wxKeyEvent keyEvt( event );
5416 keyEvt.SetEventObject( parent );
5417
5418 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
f85afd4e 5419 {
9b4aede2 5420
2d66e025
MB
5421 // try local handlers
5422 //
5423 switch ( event.KeyCode() )
5424 {
5425 case WXK_UP:
5426 if ( event.ControlDown() )
5427 {
5c8fc7c1 5428 MoveCursorUpBlock( event.ShiftDown() );
2d66e025
MB
5429 }
5430 else
5431 {
5c8fc7c1 5432 MoveCursorUp( event.ShiftDown() );
2d66e025
MB
5433 }
5434 break;
f85afd4e 5435
2d66e025
MB
5436 case WXK_DOWN:
5437 if ( event.ControlDown() )
5438 {
5c8fc7c1 5439 MoveCursorDownBlock( event.ShiftDown() );
2d66e025
MB
5440 }
5441 else
5442 {
5c8fc7c1 5443 MoveCursorDown( event.ShiftDown() );
2d66e025
MB
5444 }
5445 break;
8f177c8e 5446
2d66e025
MB
5447 case WXK_LEFT:
5448 if ( event.ControlDown() )
5449 {
5c8fc7c1 5450 MoveCursorLeftBlock( event.ShiftDown() );
2d66e025
MB
5451 }
5452 else
5453 {
5c8fc7c1 5454 MoveCursorLeft( event.ShiftDown() );
2d66e025
MB
5455 }
5456 break;
5457
5458 case WXK_RIGHT:
5459 if ( event.ControlDown() )
5460 {
5c8fc7c1 5461 MoveCursorRightBlock( event.ShiftDown() );
2d66e025
MB
5462 }
5463 else
5464 {
5c8fc7c1 5465 MoveCursorRight( event.ShiftDown() );
2d66e025
MB
5466 }
5467 break;
b99be8fb 5468
2d66e025 5469 case WXK_RETURN:
a4f7bf58 5470 case WXK_NUMPAD_ENTER:
58dd5b3b
MB
5471 if ( event.ControlDown() )
5472 {
5473 event.Skip(); // to let the edit control have the return
5474 }
5475 else
5476 {
f6bcfd97
BP
5477 if ( GetGridCursorRow() < GetNumberRows()-1 )
5478 {
5479 MoveCursorDown( event.ShiftDown() );
5480 }
5481 else
5482 {
5483 // at the bottom of a column
5484 HideCellEditControl();
5485 SaveEditControlValue();
5486 }
58dd5b3b 5487 }
2d66e025
MB
5488 break;
5489
5c8fc7c1 5490 case WXK_ESCAPE:
e32352cf 5491 ClearSelection();
5c8fc7c1
SN
5492 break;
5493
2c9a89e0
RD
5494 case WXK_TAB:
5495 if (event.ShiftDown())
f6bcfd97
BP
5496 {
5497 if ( GetGridCursorCol() > 0 )
5498 {
5499 MoveCursorLeft( FALSE );
5500 }
5501 else
5502 {
5503 // at left of grid
5504 HideCellEditControl();
5505 SaveEditControlValue();
5506 }
5507 }
2c9a89e0 5508 else
f6bcfd97
BP
5509 {
5510 if ( GetGridCursorCol() < GetNumberCols()-1 )
5511 {
5512 MoveCursorRight( FALSE );
5513 }
5514 else
5515 {
5516 // at right of grid
5517 HideCellEditControl();
5518 SaveEditControlValue();
5519 }
5520 }
2c9a89e0
RD
5521 break;
5522
2d66e025
MB
5523 case WXK_HOME:
5524 if ( event.ControlDown() )
5525 {
5526 MakeCellVisible( 0, 0 );
5527 SetCurrentCell( 0, 0 );
5528 }
5529 else
5530 {
5531 event.Skip();
5532 }
5533 break;
5534
5535 case WXK_END:
5536 if ( event.ControlDown() )
5537 {
5538 MakeCellVisible( m_numRows-1, m_numCols-1 );
5539 SetCurrentCell( m_numRows-1, m_numCols-1 );
5540 }
5541 else
5542 {
5543 event.Skip();
5544 }
5545 break;
5546
5547 case WXK_PRIOR:
5548 MovePageUp();
5549 break;
5550
5551 case WXK_NEXT:
5552 MovePageDown();
5553 break;
5554
07296f0b 5555 case WXK_SPACE:
aa5e1f75
SN
5556 if ( event.ControlDown() )
5557 {
5558 m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(),
5559 m_currentCellCoords.GetCol(),
5560 event.ControlDown(),
5561 event.ShiftDown(),
5562 event.AltDown(),
5563 event.MetaDown() );
5564 break;
5565 }
07296f0b
RD
5566 if ( !IsEditable() )
5567 {
5c8fc7c1 5568 MoveCursorRight( FALSE );
07296f0b
RD
5569 break;
5570 }
5571 // Otherwise fall through to default
5572
2d66e025 5573 default:
f6bcfd97
BP
5574 // is it possible to edit the current cell at all?
5575 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
b54ba671 5576 {
f6bcfd97 5577 // yes, now check whether the cells editor accepts the key
f2d76237
RD
5578 int row = m_currentCellCoords.GetRow();
5579 int col = m_currentCellCoords.GetCol();
5580 wxGridCellAttr* attr = GetCellAttr(row, col);
0b190b0f 5581 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
f6bcfd97
BP
5582
5583 // <F2> is special and will always start editing, for
5584 // other keys - ask the editor itself
5585 if ( (event.KeyCode() == WXK_F2 && !event.HasModifiers())
5586 || editor->IsAcceptedKey(event) )
5587 {
5588 EnableCellEditControl();
5589 editor->StartingKey(event);
5590 }
5591 else
5592 {
5593 event.Skip();
5594 }
5595
0b190b0f 5596 editor->DecRef();
2c9a89e0
RD
5597 attr->DecRef();
5598 }
b3a7510d
VZ
5599 else
5600 {
b94ae1ea
VZ
5601 // let others process char events with modifiers or all
5602 // char events for readonly cells
b3a7510d
VZ
5603 event.Skip();
5604 }
025562fe 5605 break;
2d66e025 5606 }
f85afd4e
MB
5607 }
5608
2d66e025 5609 m_inOnKeyDown = FALSE;
f85afd4e
MB
5610}
5611
f6bcfd97
BP
5612void wxGrid::OnKeyUp( wxKeyEvent& event )
5613{
5614 // try local handlers
5615 //
5616 if ( event.KeyCode() == WXK_SHIFT )
5617 {
5618 if ( m_selectingTopLeft != wxGridNoCellCoords &&
5619 m_selectingBottomRight != wxGridNoCellCoords )
5620 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
5621 m_selectingTopLeft.GetCol(),
5622 m_selectingBottomRight.GetRow(),
5623 m_selectingBottomRight.GetCol(),
5624 event.ControlDown(),
5625 TRUE,
5626 event.AltDown(),
5627 event.MetaDown() );
5628 m_selectingTopLeft = wxGridNoCellCoords;
5629 m_selectingBottomRight = wxGridNoCellCoords;
5630 m_selectingKeyboard = wxGridNoCellCoords;
5631 }
5632}
5633
2796cce3 5634void wxGrid::OnEraseBackground(wxEraseEvent&)
508011ce
VZ
5635{
5636}
07296f0b 5637
2d66e025 5638void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
66242c80 5639{
f6bcfd97
BP
5640 if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
5641 {
5642 // the event has been intercepted - do nothing
5643 return;
5644 }
5645
5646 wxClientDC dc(m_gridWin);
5647 PrepareDC(dc);
5648
2a7750d9 5649 if ( m_currentCellCoords != wxGridNoCellCoords )
2d66e025 5650 {
2d66e025 5651 HideCellEditControl();
b54ba671 5652 DisableCellEditControl();
07296f0b 5653
3ca6a5f0 5654 if ( IsVisible( m_currentCellCoords, FALSE ) )
f6bcfd97
BP
5655 {
5656 wxRect r;
5657 r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords);
5658 if ( !m_gridLinesEnabled )
5659 {
5660 r.x--;
5661 r.y--;
5662 r.width++;
5663 r.height++;
5664 }
d1c0b4f9 5665
f6bcfd97 5666 CalcCellsExposed( r );
84912ef8 5667
f6bcfd97
BP
5668 // Otherwise refresh redraws the highlight!
5669 m_currentCellCoords = coords;
d1c0b4f9 5670
f6bcfd97
BP
5671 DrawGridCellArea(dc);
5672 DrawAllGridLines( dc, r );
5673 }
66242c80 5674 }
8f177c8e 5675
2d66e025
MB
5676 m_currentCellCoords = coords;
5677
2a7750d9
MB
5678 wxGridCellAttr* attr = GetCellAttr(coords);
5679 DrawCellHighlight(dc, attr);
5680 attr->DecRef();
66242c80
MB
5681}
5682
2d66e025 5683
c9097836
MB
5684void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCol )
5685{
5686 int temp;
5687 wxGridCellCoords updateTopLeft, updateBottomRight;
5688
5689 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
5690 {
5691 leftCol = 0;
5692 rightCol = GetNumberCols() - 1;
5693 }
5694 else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
5695 {
5696 topRow = 0;
5697 bottomRow = GetNumberRows() - 1;
5698 }
5699 if ( topRow > bottomRow )
5700 {
5701 temp = topRow;
5702 topRow = bottomRow;
5703 bottomRow = temp;
5704 }
5705
5706 if ( leftCol > rightCol )
5707 {
5708 temp = leftCol;
5709 leftCol = rightCol;
5710 rightCol = temp;
5711 }
5712
5713 updateTopLeft = wxGridCellCoords( topRow, leftCol );
5714 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
5715
5716 if ( m_selectingTopLeft != updateTopLeft ||
5717 m_selectingBottomRight != updateBottomRight )
5718 {
5719 // Compute two optimal update rectangles:
5720 // Either one rectangle is a real subset of the
5721 // other, or they are (almost) disjoint!
5722 wxRect rect[4];
5723 bool need_refresh[4];
5724 need_refresh[0] =
5725 need_refresh[1] =
5726 need_refresh[2] =
5727 need_refresh[3] = FALSE;
5728 int i;
5729
5730 // Store intermediate values
5731 wxCoord oldLeft = m_selectingTopLeft.GetCol();
5732 wxCoord oldTop = m_selectingTopLeft.GetRow();
5733 wxCoord oldRight = m_selectingBottomRight.GetCol();
5734 wxCoord oldBottom = m_selectingBottomRight.GetRow();
5735
5736 // Determine the outer/inner coordinates.
5737 if (oldLeft > leftCol)
5738 {
5739 temp = oldLeft;
5740 oldLeft = leftCol;
5741 leftCol = temp;
5742 }
5743 if (oldTop > topRow )
5744 {
5745 temp = oldTop;
5746 oldTop = topRow;
5747 topRow = temp;
5748 }
5749 if (oldRight < rightCol )
5750 {
5751 temp = oldRight;
5752 oldRight = rightCol;
5753 rightCol = temp;
5754 }
5755 if (oldBottom < bottomRow)
5756 {
5757 temp = oldBottom;
5758 oldBottom = bottomRow;
5759 bottomRow = temp;
5760 }
5761
5762 // Now, either the stuff marked old is the outer
5763 // rectangle or we don't have a situation where one
5764 // is contained in the other.
5765
5766 if ( oldLeft < leftCol )
5767 {
5768 need_refresh[0] = TRUE;
5769 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5770 oldLeft ),
5771 wxGridCellCoords ( oldBottom,
5772 leftCol - 1 ) );
5773 }
5774
5775 if ( oldTop < topRow )
5776 {
5777 need_refresh[1] = TRUE;
5778 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5779 leftCol ),
5780 wxGridCellCoords ( topRow - 1,
5781 rightCol ) );
5782 }
5783
5784 if ( oldRight > rightCol )
5785 {
5786 need_refresh[2] = TRUE;
5787 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5788 rightCol + 1 ),
5789 wxGridCellCoords ( oldBottom,
5790 oldRight ) );
5791 }
5792
5793 if ( oldBottom > bottomRow )
5794 {
5795 need_refresh[3] = TRUE;
5796 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
5797 leftCol ),
5798 wxGridCellCoords ( oldBottom,
5799 rightCol ) );
5800 }
5801
5802
5803 // Change Selection
5804 m_selectingTopLeft = updateTopLeft;
5805 m_selectingBottomRight = updateBottomRight;
5806
5807 // various Refresh() calls
5808 for (i = 0; i < 4; i++ )
5809 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5810 m_gridWin->Refresh( FALSE, &(rect[i]) );
5811 }
5812
5813 // never generate an event as it will be generated from
5814 // wxGridSelection::SelectBlock!
5815 // (old comment from when this was the body of SelectBlock)
5816}
5817
2d66e025
MB
5818//
5819// ------ functions to get/send data (see also public functions)
5820//
5821
5822bool wxGrid::GetModelValues()
66242c80 5823{
2d66e025 5824 if ( m_table )
66242c80 5825 {
2d66e025 5826 // all we need to do is repaint the grid
66242c80 5827 //
2d66e025 5828 m_gridWin->Refresh();
66242c80
MB
5829 return TRUE;
5830 }
8f177c8e 5831
66242c80
MB
5832 return FALSE;
5833}
5834
2d66e025
MB
5835
5836bool wxGrid::SetModelValues()
f85afd4e 5837{
2d66e025 5838 int row, col;
8f177c8e 5839
2d66e025
MB
5840 if ( m_table )
5841 {
5842 for ( row = 0; row < m_numRows; row++ )
f85afd4e 5843 {
2d66e025 5844 for ( col = 0; col < m_numCols; col++ )
f85afd4e 5845 {
2d66e025 5846 m_table->SetValue( row, col, GetCellValue(row, col) );
f85afd4e
MB
5847 }
5848 }
8f177c8e 5849
f85afd4e
MB
5850 return TRUE;
5851 }
5852
5853 return FALSE;
5854}
5855
2d66e025
MB
5856
5857
5858// Note - this function only draws cells that are in the list of
5859// exposed cells (usually set from the update region by
5860// CalcExposedCells)
5861//
5862void wxGrid::DrawGridCellArea( wxDC& dc )
f85afd4e 5863{
2d66e025 5864 if ( !m_numRows || !m_numCols ) return;
60ff3b99 5865
2d66e025
MB
5866 size_t i;
5867 size_t numCells = m_cellsExposed.GetCount();
60ff3b99 5868
2d66e025 5869 for ( i = 0; i < numCells; i++ )
f85afd4e 5870 {
2d66e025
MB
5871 DrawCell( dc, m_cellsExposed[i] );
5872 }
5873}
8f177c8e 5874
8f177c8e 5875
7c8a8ad5
MB
5876void wxGrid::DrawGridSpace( wxDC& dc )
5877{
f6bcfd97
BP
5878 int cw, ch;
5879 m_gridWin->GetClientSize( &cw, &ch );
7c8a8ad5 5880
f6bcfd97
BP
5881 int right, bottom;
5882 CalcUnscrolledPosition( cw, ch, &right, &bottom );
7c8a8ad5 5883
f6bcfd97
BP
5884 int rightCol = m_numCols > 0 ? GetColRight(m_numCols - 1) : 0;
5885 int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0 ;
7c8a8ad5 5886
f6bcfd97
BP
5887 if ( right > rightCol || bottom > bottomRow )
5888 {
5889 int left, top;
5890 CalcUnscrolledPosition( 0, 0, &left, &top );
7c8a8ad5 5891
f6bcfd97
BP
5892 dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
5893 dc.SetPen( *wxTRANSPARENT_PEN );
7c8a8ad5 5894
f6bcfd97
BP
5895 if ( right > rightCol )
5896 {
5897 dc.DrawRectangle( rightCol, top, right - rightCol, ch);
5898 }
5899
5900 if ( bottom > bottomRow )
5901 {
5902 dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow);
5903 }
5904 }
7c8a8ad5
MB
5905}
5906
5907
2d66e025
MB
5908void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
5909{
ab79958a
VZ
5910 int row = coords.GetRow();
5911 int col = coords.GetCol();
60ff3b99 5912
7c1cb261 5913 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
ab79958a
VZ
5914 return;
5915
5916 // we draw the cell border ourselves
9496deb5 5917#if !WXGRID_DRAW_LINES
2d66e025
MB
5918 if ( m_gridLinesEnabled )
5919 DrawCellBorder( dc, coords );
796df70a 5920#endif
f85afd4e 5921
189d0213
VZ
5922 wxGridCellAttr* attr = GetCellAttr(row, col);
5923
5924 bool isCurrent = coords == m_currentCellCoords;
508011ce 5925
f6bcfd97 5926 wxRect rect = CellToRect( row, col );
f85afd4e 5927
189d0213 5928 // if the editor is shown, we should use it and not the renderer
f6bcfd97
BP
5929 // Note: However, only if it is really _shown_, i.e. not hidden!
5930 if ( isCurrent && IsCellEditControlShown() )
189d0213 5931 {
0b190b0f
VZ
5932 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
5933 editor->PaintBackground(rect, attr);
5934 editor->DecRef();
189d0213
VZ
5935 }
5936 else
5937 {
5938 // but all the rest is drawn by the cell renderer and hence may be
5939 // customized
0b190b0f
VZ
5940 wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
5941 renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
5942 renderer->DecRef();
189d0213 5943 }
07296f0b 5944
283b7808
VZ
5945 attr->DecRef();
5946}
07296f0b 5947
283b7808 5948void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr )
07296f0b
RD
5949{
5950 int row = m_currentCellCoords.GetRow();
5951 int col = m_currentCellCoords.GetCol();
5952
7c1cb261 5953 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
07296f0b
RD
5954 return;
5955
f6bcfd97 5956 wxRect rect = CellToRect(row, col);
07296f0b 5957
b3a7510d
VZ
5958 // hmmm... what could we do here to show that the cell is disabled?
5959 // for now, I just draw a thinner border than for the other ones, but
5960 // it doesn't look really good
f6bcfd97 5961 dc.SetPen(wxPen(m_cellHighlightColour, attr->IsReadOnly() ? 1 : 3, wxSOLID));
b3a7510d
VZ
5962 dc.SetBrush(*wxTRANSPARENT_BRUSH);
5963
5964 dc.DrawRectangle(rect);
07296f0b 5965
283b7808 5966#if 0
b3a7510d 5967 // VZ: my experiments with 3d borders...
283b7808 5968
b3a7510d 5969 // how to properly set colours for arbitrary bg?
283b7808
VZ
5970 wxCoord x1 = rect.x,
5971 y1 = rect.y,
00cf1208
RR
5972 x2 = rect.x + rect.width -1,
5973 y2 = rect.y + rect.height -1;
283b7808
VZ
5974
5975 dc.SetPen(*wxWHITE_PEN);
00cf1208
RR
5976 dc.DrawLine(x1, y1, x2, y1);
5977 dc.DrawLine(x1, y1, x1, y2);
283b7808 5978
283b7808 5979 dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
00cf1208 5980 dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2 );
283b7808
VZ
5981
5982 dc.SetPen(*wxBLACK_PEN);
5983 dc.DrawLine(x1, y2, x2, y2);
00cf1208 5984 dc.DrawLine(x2, y1, x2, y2+1);
b3a7510d 5985#endif // 0
2d66e025 5986}
f85afd4e 5987
f2d76237 5988
2d66e025
MB
5989void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
5990{
2d66e025
MB
5991 int row = coords.GetRow();
5992 int col = coords.GetCol();
7c1cb261
VZ
5993 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5994 return;
5995
5996 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
60ff3b99 5997
2d66e025
MB
5998 // right hand border
5999 //
7c1cb261
VZ
6000 dc.DrawLine( GetColRight(col), GetRowTop(row),
6001 GetColRight(col), GetRowBottom(row) );
2d66e025
MB
6002
6003 // bottom border
6004 //
7c1cb261
VZ
6005 dc.DrawLine( GetColLeft(col), GetRowBottom(row),
6006 GetColRight(col), GetRowBottom(row) );
f85afd4e
MB
6007}
6008
b3a7510d
VZ
6009void wxGrid::DrawHighlight(wxDC& dc)
6010{
2a7750d9
MB
6011 // This if block was previously in wxGrid::OnPaint but that doesn't
6012 // seem to get called under wxGTK - MB
6013 //
6014 if ( m_currentCellCoords == wxGridNoCellCoords &&
6015 m_numRows && m_numCols )
6016 {
6017 m_currentCellCoords.Set(0, 0);
6018 }
6019
f6bcfd97 6020 if ( IsCellEditControlShown() )
99306db2
VZ
6021 {
6022 // don't show highlight when the edit control is shown
6023 return;
6024 }
6025
b3a7510d
VZ
6026 // if the active cell was repainted, repaint its highlight too because it
6027 // might have been damaged by the grid lines
6028 size_t count = m_cellsExposed.GetCount();
6029 for ( size_t n = 0; n < count; n++ )
6030 {
6031 if ( m_cellsExposed[n] == m_currentCellCoords )
6032 {
6033 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
6034 DrawCellHighlight(dc, attr);
6035 attr->DecRef();
6036
6037 break;
6038 }
6039 }
6040}
2d66e025 6041
2d66e025
MB
6042// TODO: remove this ???
6043// This is used to redraw all grid lines e.g. when the grid line colour
6044// has been changed
6045//
c78b3acd 6046void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED_GTK(reg) )
f85afd4e 6047{
60ff3b99
VZ
6048 if ( !m_gridLinesEnabled ||
6049 !m_numRows ||
2d66e025 6050 !m_numCols ) return;
f85afd4e 6051
2d66e025 6052 int top, bottom, left, right;
796df70a 6053
f6bcfd97 6054#if 0 //#ifndef __WXGTK__
508011ce
VZ
6055 if (reg.IsEmpty())
6056 {
796df70a
SN
6057 int cw, ch;
6058 m_gridWin->GetClientSize(&cw, &ch);
6059
6060 // virtual coords of visible area
6061 //
6062 CalcUnscrolledPosition( 0, 0, &left, &top );
6063 CalcUnscrolledPosition( cw, ch, &right, &bottom );
6064 }
508011ce
VZ
6065 else
6066 {
796df70a
SN
6067 wxCoord x, y, w, h;
6068 reg.GetBox(x, y, w, h);
6069 CalcUnscrolledPosition( x, y, &left, &top );
6070 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
6071 }
8e217128
RR
6072#else
6073 int cw, ch;
6074 m_gridWin->GetClientSize(&cw, &ch);
6075 CalcUnscrolledPosition( 0, 0, &left, &top );
6076 CalcUnscrolledPosition( cw, ch, &right, &bottom );
6077#endif
f85afd4e 6078
9496deb5
MB
6079 // avoid drawing grid lines past the last row and col
6080 //
7c1cb261
VZ
6081 right = wxMin( right, GetColRight(m_numCols - 1) );
6082 bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
9496deb5 6083
2d66e025 6084 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
f85afd4e 6085
2d66e025 6086 // horizontal grid lines
f85afd4e 6087 //
60ff3b99 6088 int i;
9496deb5 6089 for ( i = 0; i < m_numRows; i++ )
f85afd4e 6090 {
6d55126d 6091 int bot = GetRowBottom(i) - 1;
7c1cb261 6092
6d55126d 6093 if ( bot > bottom )
2d66e025
MB
6094 {
6095 break;
6096 }
7c1cb261 6097
6d55126d 6098 if ( bot >= top )
2d66e025 6099 {
6d55126d 6100 dc.DrawLine( left, bot, right, bot );
2d66e025 6101 }
f85afd4e
MB
6102 }
6103
f85afd4e 6104
2d66e025
MB
6105 // vertical grid lines
6106 //
9496deb5 6107 for ( i = 0; i < m_numCols; i++ )
f85afd4e 6108 {
7c1cb261
VZ
6109 int colRight = GetColRight(i) - 1;
6110 if ( colRight > right )
2d66e025
MB
6111 {
6112 break;
6113 }
7c1cb261
VZ
6114
6115 if ( colRight >= left )
2d66e025 6116 {
7c1cb261 6117 dc.DrawLine( colRight, top, colRight, bottom );
2d66e025
MB
6118 }
6119 }
6120}
f85afd4e 6121
8f177c8e 6122
2d66e025
MB
6123void wxGrid::DrawRowLabels( wxDC& dc )
6124{
f6bcfd97 6125 if ( !m_numRows ) return;
60ff3b99 6126
2d66e025
MB
6127 size_t i;
6128 size_t numLabels = m_rowLabelsExposed.GetCount();
60ff3b99 6129
2d66e025
MB
6130 for ( i = 0; i < numLabels; i++ )
6131 {
6132 DrawRowLabel( dc, m_rowLabelsExposed[i] );
60ff3b99 6133 }
f85afd4e
MB
6134}
6135
6136
2d66e025 6137void wxGrid::DrawRowLabel( wxDC& dc, int row )
f85afd4e 6138{
7c1cb261
VZ
6139 if ( GetRowHeight(row) <= 0 )
6140 return;
60ff3b99 6141
7c1cb261
VZ
6142 int rowTop = GetRowTop(row),
6143 rowBottom = GetRowBottom(row) - 1;
b99be8fb 6144
2d66e025 6145 dc.SetPen( *wxBLACK_PEN );
b0d6ff2f 6146 dc.DrawLine( m_rowLabelWidth-1, rowTop,
7c1cb261 6147 m_rowLabelWidth-1, rowBottom );
b99be8fb 6148
7c1cb261 6149 dc.DrawLine( 0, rowBottom, m_rowLabelWidth-1, rowBottom );
b99be8fb 6150
2d66e025 6151 dc.SetPen( *wxWHITE_PEN );
7c1cb261 6152 dc.DrawLine( 0, rowTop, 0, rowBottom );
b0d6ff2f 6153 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
60ff3b99 6154
f85afd4e 6155 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
6156 dc.SetTextForeground( GetLabelTextColour() );
6157 dc.SetFont( GetLabelFont() );
8f177c8e 6158
f85afd4e 6159 int hAlign, vAlign;
2d66e025 6160 GetRowLabelAlignment( &hAlign, &vAlign );
60ff3b99 6161
2d66e025
MB
6162 wxRect rect;
6163 rect.SetX( 2 );
7c1cb261 6164 rect.SetY( GetRowTop(row) + 2 );
2d66e025 6165 rect.SetWidth( m_rowLabelWidth - 4 );
7c1cb261 6166 rect.SetHeight( GetRowHeight(row) - 4 );
60ff3b99 6167 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
f85afd4e
MB
6168}
6169
6170
2d66e025 6171void wxGrid::DrawColLabels( wxDC& dc )
f85afd4e 6172{
f6bcfd97 6173 if ( !m_numCols ) return;
60ff3b99 6174
2d66e025
MB
6175 size_t i;
6176 size_t numLabels = m_colLabelsExposed.GetCount();
60ff3b99 6177
2d66e025 6178 for ( i = 0; i < numLabels; i++ )
f85afd4e 6179 {
2d66e025 6180 DrawColLabel( dc, m_colLabelsExposed[i] );
60ff3b99 6181 }
f85afd4e
MB
6182}
6183
6184
2d66e025 6185void wxGrid::DrawColLabel( wxDC& dc, int col )
f85afd4e 6186{
7c1cb261
VZ
6187 if ( GetColWidth(col) <= 0 )
6188 return;
60ff3b99 6189
7c1cb261
VZ
6190 int colLeft = GetColLeft(col),
6191 colRight = GetColRight(col) - 1;
b99be8fb 6192
2d66e025 6193 dc.SetPen( *wxBLACK_PEN );
7c1cb261
VZ
6194 dc.DrawLine( colRight, 0,
6195 colRight, m_colLabelHeight-1 );
b99be8fb 6196
b0d6ff2f 6197 dc.DrawLine( colLeft, m_colLabelHeight-1,
7c1cb261 6198 colRight, m_colLabelHeight-1 );
b99be8fb 6199
f85afd4e 6200 dc.SetPen( *wxWHITE_PEN );
b0d6ff2f 6201 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
7c1cb261 6202 dc.DrawLine( colLeft, 0, colRight, 0 );
f85afd4e 6203
b0d6ff2f
MB
6204 dc.SetBackgroundMode( wxTRANSPARENT );
6205 dc.SetTextForeground( GetLabelTextColour() );
6206 dc.SetFont( GetLabelFont() );
8f177c8e 6207
f85afd4e 6208 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
6209 dc.SetTextForeground( GetLabelTextColour() );
6210 dc.SetFont( GetLabelFont() );
8f177c8e 6211
f85afd4e 6212 int hAlign, vAlign;
2d66e025 6213 GetColLabelAlignment( &hAlign, &vAlign );
60ff3b99 6214
2d66e025 6215 wxRect rect;
7c1cb261 6216 rect.SetX( colLeft + 2 );
2d66e025 6217 rect.SetY( 2 );
7c1cb261 6218 rect.SetWidth( GetColWidth(col) - 4 );
2d66e025 6219 rect.SetHeight( m_colLabelHeight - 4 );
60ff3b99 6220 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
f85afd4e
MB
6221}
6222
6223
2d66e025
MB
6224void wxGrid::DrawTextRectangle( wxDC& dc,
6225 const wxString& value,
6226 const wxRect& rect,
6227 int horizAlign,
6228 int vertAlign )
f85afd4e 6229{
2d66e025
MB
6230 long textWidth, textHeight;
6231 long lineWidth, lineHeight;
6232 wxArrayString lines;
f85afd4e 6233
2d66e025
MB
6234 dc.SetClippingRegion( rect );
6235 StringToLines( value, lines );
6236 if ( lines.GetCount() )
6237 {
6238 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
6239 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
f85afd4e 6240
2d66e025
MB
6241 float x, y;
6242 switch ( horizAlign )
6243 {
4c7277db 6244 case wxALIGN_RIGHT:
2d66e025
MB
6245 x = rect.x + (rect.width - textWidth - 1);
6246 break;
f85afd4e 6247
4c7277db 6248 case wxALIGN_CENTRE:
2d66e025
MB
6249 x = rect.x + ((rect.width - textWidth)/2);
6250 break;
f85afd4e 6251
4c7277db 6252 case wxALIGN_LEFT:
2d66e025
MB
6253 default:
6254 x = rect.x + 1;
6255 break;
6256 }
f85afd4e 6257
2d66e025
MB
6258 switch ( vertAlign )
6259 {
4c7277db 6260 case wxALIGN_BOTTOM:
2d66e025
MB
6261 y = rect.y + (rect.height - textHeight - 1);
6262 break;
f85afd4e 6263
4c7277db 6264 case wxALIGN_CENTRE:
8f177c8e 6265 y = rect.y + ((rect.height - textHeight)/2);
f85afd4e
MB
6266 break;
6267
4c7277db 6268 case wxALIGN_TOP:
f85afd4e 6269 default:
8f177c8e 6270 y = rect.y + 1;
f85afd4e
MB
6271 break;
6272 }
6273
b540eb2b 6274 for ( size_t i = 0; i < lines.GetCount(); i++ )
f85afd4e 6275 {
4a64bee4 6276 dc.DrawText( lines[i], (int)x, (int)y );
f85afd4e
MB
6277 y += lineHeight;
6278 }
6279 }
8f177c8e 6280
f85afd4e 6281 dc.DestroyClippingRegion();
f85afd4e
MB
6282}
6283
6284
6285// Split multi line text up into an array of strings. Any existing
6286// contents of the string array are preserved.
6287//
6288void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
6289{
f85afd4e
MB
6290 int startPos = 0;
6291 int pos;
6d004f67 6292 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
2433bb2e 6293 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
e2b42eeb 6294
2433bb2e 6295 while ( startPos < (int)tVal.Length() )
f85afd4e 6296 {
2433bb2e 6297 pos = tVal.Mid(startPos).Find( eol );
f85afd4e
MB
6298 if ( pos < 0 )
6299 {
6300 break;
6301 }
6302 else if ( pos == 0 )
6303 {
6304 lines.Add( wxEmptyString );
6305 }
6306 else
6307 {
2433bb2e 6308 lines.Add( value.Mid(startPos, pos) );
f85afd4e
MB
6309 }
6310 startPos += pos+1;
6311 }
b540eb2b 6312 if ( startPos < (int)value.Length() )
f85afd4e
MB
6313 {
6314 lines.Add( value.Mid( startPos ) );
6315 }
6316}
6317
6318
6319void wxGrid::GetTextBoxSize( wxDC& dc,
6320 wxArrayString& lines,
6321 long *width, long *height )
6322{
6323 long w = 0;
6324 long h = 0;
6325 long lineW, lineH;
6326
b540eb2b 6327 size_t i;
f85afd4e
MB
6328 for ( i = 0; i < lines.GetCount(); i++ )
6329 {
6330 dc.GetTextExtent( lines[i], &lineW, &lineH );
6331 w = wxMax( w, lineW );
6332 h += lineH;
6333 }
6334
6335 *width = w;
6336 *height = h;
6337}
6338
f6bcfd97
BP
6339//
6340// ------ Batch processing.
6341//
6342void wxGrid::EndBatch()
6343{
6344 if ( m_batchCount > 0 )
6345 {
6346 m_batchCount--;
6347 if ( !m_batchCount )
6348 {
6349 CalcDimensions();
6350 m_rowLabelWin->Refresh();
6351 m_colLabelWin->Refresh();
6352 m_cornerLabelWin->Refresh();
6353 m_gridWin->Refresh();
6354 }
6355 }
6356}
f85afd4e 6357
d8232393
MB
6358// Use this, rather than wxWindow::Refresh(), to force an immediate
6359// repainting of the grid. Has no effect if you are already inside a
6360// BeginBatch / EndBatch block.
6361//
6362void wxGrid::ForceRefresh()
6363{
6364 BeginBatch();
6365 EndBatch();
6366}
6367
6368
f85afd4e 6369//
2d66e025 6370// ------ Edit control functions
f85afd4e
MB
6371//
6372
2d66e025
MB
6373
6374void wxGrid::EnableEditing( bool edit )
f85afd4e 6375{
2d66e025
MB
6376 // TODO: improve this ?
6377 //
6378 if ( edit != m_editable )
f85afd4e 6379 {
632efa47 6380 if(!edit) EnableCellEditControl(edit);
2d66e025 6381 m_editable = edit;
f85afd4e 6382 }
f85afd4e
MB
6383}
6384
6385
2d66e025 6386void wxGrid::EnableCellEditControl( bool enable )
f85afd4e 6387{
2c9a89e0
RD
6388 if (! m_editable)
6389 return;
6390
dcfe4c3d
SN
6391 if ( m_currentCellCoords == wxGridNoCellCoords )
6392 SetCurrentCell( 0, 0 );
60ff3b99 6393
2c9a89e0
RD
6394 if ( enable != m_cellEditCtrlEnabled )
6395 {
b54ba671
VZ
6396 // TODO allow the app to Veto() this event?
6397 SendEvent(enable ? wxEVT_GRID_EDITOR_SHOWN : wxEVT_GRID_EDITOR_HIDDEN);
6398
dcfe4c3d 6399 if ( enable )
f85afd4e 6400 {
b54ba671
VZ
6401 // this should be checked by the caller!
6402 wxASSERT_MSG( CanEnableCellControl(),
6403 _T("can't enable editing for this cell!") );
6404
6405 // do it before ShowCellEditControl()
dcfe4c3d 6406 m_cellEditCtrlEnabled = enable;
b54ba671 6407
2d66e025 6408 ShowCellEditControl();
2d66e025
MB
6409 }
6410 else
6411 {
2d66e025
MB
6412 HideCellEditControl();
6413 SaveEditControlValue();
b54ba671
VZ
6414
6415 // do it after HideCellEditControl()
dcfe4c3d 6416 m_cellEditCtrlEnabled = enable;
f85afd4e 6417 }
f85afd4e 6418 }
f85afd4e 6419}
f85afd4e 6420
b54ba671 6421bool wxGrid::IsCurrentCellReadOnly() const
283b7808 6422{
b54ba671
VZ
6423 // const_cast
6424 wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords);
6425 bool readonly = attr->IsReadOnly();
6426 attr->DecRef();
283b7808 6427
b54ba671
VZ
6428 return readonly;
6429}
283b7808 6430
b54ba671
VZ
6431bool wxGrid::CanEnableCellControl() const
6432{
6433 return m_editable && !IsCurrentCellReadOnly();
6434}
6435
6436bool wxGrid::IsCellEditControlEnabled() const
6437{
6438 // the cell edit control might be disable for all cells or just for the
6439 // current one if it's read only
6440 return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE;
283b7808
VZ
6441}
6442
f6bcfd97
BP
6443bool wxGrid::IsCellEditControlShown() const
6444{
6445 bool isShown = FALSE;
6446
6447 if ( m_cellEditCtrlEnabled )
6448 {
6449 int row = m_currentCellCoords.GetRow();
6450 int col = m_currentCellCoords.GetCol();
6451 wxGridCellAttr* attr = GetCellAttr(row, col);
6452 wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col);
6453 attr->DecRef();
6454
6455 if ( editor )
6456 {
6457 if ( editor->IsCreated() )
6458 {
6459 isShown = editor->GetControl()->IsShown();
6460 }
6461
6462 editor->DecRef();
6463 }
6464 }
6465
6466 return isShown;
6467}
6468
2d66e025 6469void wxGrid::ShowCellEditControl()
f85afd4e 6470{
2d66e025 6471 if ( IsCellEditControlEnabled() )
f85afd4e 6472 {
2d66e025
MB
6473 if ( !IsVisible( m_currentCellCoords ) )
6474 {
3ca6a5f0 6475 m_cellEditCtrlEnabled = FALSE;
2d66e025
MB
6476 return;
6477 }
6478 else
6479 {
2c9a89e0
RD
6480 wxRect rect = CellToRect( m_currentCellCoords );
6481 int row = m_currentCellCoords.GetRow();
6482 int col = m_currentCellCoords.GetCol();
2d66e025
MB
6483
6484 // convert to scrolled coords
6485 //
99306db2 6486 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
508011ce 6487
99306db2
VZ
6488 // done in PaintBackground()
6489#if 0
6490 // erase the highlight and the cell contents because the editor
6491 // might not cover the entire cell
6492 wxClientDC dc( m_gridWin );
6493 PrepareDC( dc );
6494 dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
6495 dc.SetPen(*wxTRANSPARENT_PEN);
6496 dc.DrawRectangle(rect);
6497#endif // 0
d2fdd8d2 6498
99306db2
VZ
6499 // cell is shifted by one pixel
6500 rect.x--;
6501 rect.y--;
f0102d2a 6502
508011ce 6503 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 6504 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
3da93aae
VZ
6505 if ( !editor->IsCreated() )
6506 {
2c9a89e0
RD
6507 editor->Create(m_gridWin, -1,
6508 new wxGridCellEditorEvtHandler(this, editor));
2d66e025
MB
6509 }
6510
b0e282b3 6511 editor->Show( TRUE, attr );
0b190b0f 6512
2c9a89e0 6513 editor->SetSize( rect );
99306db2 6514
3da93aae 6515 editor->BeginEdit(row, col, this);
0b190b0f
VZ
6516
6517 editor->DecRef();
2c9a89e0
RD
6518 attr->DecRef();
6519 }
f85afd4e
MB
6520 }
6521}
6522
6523
2d66e025 6524void wxGrid::HideCellEditControl()
f85afd4e 6525{
2d66e025 6526 if ( IsCellEditControlEnabled() )
f85afd4e 6527 {
2c9a89e0
RD
6528 int row = m_currentCellCoords.GetRow();
6529 int col = m_currentCellCoords.GetCol();
6530
3da93aae 6531 wxGridCellAttr* attr = GetCellAttr(row, col);
0b190b0f
VZ
6532 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
6533 editor->Show( FALSE );
6534 editor->DecRef();
2c9a89e0
RD
6535 attr->DecRef();
6536 m_gridWin->SetFocus();
f6bcfd97
BP
6537 wxRect rect( CellToRect( row, col ) );
6538 m_gridWin->Refresh( FALSE, &rect );
f85afd4e 6539 }
2d66e025 6540}
8f177c8e 6541
2d66e025 6542
2d66e025
MB
6543void wxGrid::SaveEditControlValue()
6544{
3da93aae
VZ
6545 if ( IsCellEditControlEnabled() )
6546 {
2c9a89e0
RD
6547 int row = m_currentCellCoords.GetRow();
6548 int col = m_currentCellCoords.GetCol();
8f177c8e 6549
3da93aae 6550 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 6551 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
3324d5f5 6552 bool changed = editor->EndEdit(row, col, this);
2d66e025 6553
0b190b0f 6554 editor->DecRef();
2c9a89e0 6555 attr->DecRef();
2d66e025 6556
3da93aae
VZ
6557 if (changed)
6558 {
b54ba671 6559 SendEvent( wxEVT_GRID_CELL_CHANGE,
2d66e025
MB
6560 m_currentCellCoords.GetRow(),
6561 m_currentCellCoords.GetCol() );
6562 }
f85afd4e
MB
6563 }
6564}
6565
2d66e025
MB
6566
6567//
60ff3b99
VZ
6568// ------ Grid location functions
6569// Note that all of these functions work with the logical coordinates of
2d66e025
MB
6570// grid cells and labels so you will need to convert from device
6571// coordinates for mouse events etc.
6572//
6573
6574void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
f85afd4e 6575{
58dd5b3b
MB
6576 int row = YToRow(y);
6577 int col = XToCol(x);
6578
6579 if ( row == -1 || col == -1 )
6580 {
6581 coords = wxGridNoCellCoords;
6582 }
6583 else
6584 {
6585 coords.Set( row, col );
6586 }
2d66e025 6587}
f85afd4e 6588
8f177c8e 6589
2d66e025
MB
6590int wxGrid::YToRow( int y )
6591{
6592 int i;
8f177c8e 6593
2d66e025 6594 for ( i = 0; i < m_numRows; i++ )
f85afd4e 6595 {
7c1cb261
VZ
6596 if ( y < GetRowBottom(i) )
6597 return i;
f85afd4e 6598 }
2d66e025 6599
4ee5fc9c 6600 return -1;
f85afd4e
MB
6601}
6602
2d66e025
MB
6603
6604int wxGrid::XToCol( int x )
f85afd4e 6605{
2d66e025 6606 int i;
8f177c8e 6607
2d66e025 6608 for ( i = 0; i < m_numCols; i++ )
f85afd4e 6609 {
7c1cb261
VZ
6610 if ( x < GetColRight(i) )
6611 return i;
f85afd4e
MB
6612 }
6613
4ee5fc9c 6614 return -1;
2d66e025 6615}
8f177c8e 6616
2d66e025
MB
6617
6618// return the row number that that the y coord is near the edge of, or
6619// -1 if not near an edge
6620//
6621int wxGrid::YToEdgeOfRow( int y )
6622{
6623 int i, d;
6624
6625 for ( i = 0; i < m_numRows; i++ )
6626 {
7c1cb261 6627 if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
f85afd4e 6628 {
7c1cb261
VZ
6629 d = abs( y - GetRowBottom(i) );
6630 if ( d < WXGRID_LABEL_EDGE_ZONE )
6631 return i;
f85afd4e 6632 }
f85afd4e 6633 }
2d66e025
MB
6634
6635 return -1;
6636}
6637
6638
6639// return the col number that that the x coord is near the edge of, or
6640// -1 if not near an edge
6641//
6642int wxGrid::XToEdgeOfCol( int x )
6643{
6644 int i, d;
6645
6646 for ( i = 0; i < m_numCols; i++ )
f85afd4e 6647 {
7c1cb261 6648 if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
2d66e025 6649 {
7c1cb261
VZ
6650 d = abs( x - GetColRight(i) );
6651 if ( d < WXGRID_LABEL_EDGE_ZONE )
6652 return i;
2d66e025 6653 }
f85afd4e 6654 }
2d66e025
MB
6655
6656 return -1;
f85afd4e
MB
6657}
6658
2d66e025
MB
6659
6660wxRect wxGrid::CellToRect( int row, int col )
f85afd4e 6661{
2d66e025 6662 wxRect rect( -1, -1, -1, -1 );
f85afd4e 6663
2d66e025
MB
6664 if ( row >= 0 && row < m_numRows &&
6665 col >= 0 && col < m_numCols )
f85afd4e 6666 {
7c1cb261
VZ
6667 rect.x = GetColLeft(col);
6668 rect.y = GetRowTop(row);
6669 rect.width = GetColWidth(col);
6670 rect.height = GetRowHeight(row);
f85afd4e
MB
6671 }
6672
f6bcfd97
BP
6673 // if grid lines are enabled, then the area of the cell is a bit smaller
6674 if (m_gridLinesEnabled) {
6675 rect.width -= 1;
6676 rect.height -= 1;
6677 }
2d66e025
MB
6678 return rect;
6679}
6680
6681
6682bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
6683{
6684 // get the cell rectangle in logical coords
6685 //
6686 wxRect r( CellToRect( row, col ) );
60ff3b99 6687
2d66e025
MB
6688 // convert to device coords
6689 //
6690 int left, top, right, bottom;
6691 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6692 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 6693
2d66e025
MB
6694 // check against the client area of the grid window
6695 //
6696 int cw, ch;
6697 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 6698
2d66e025 6699 if ( wholeCellVisible )
f85afd4e 6700 {
2d66e025 6701 // is the cell wholly visible ?
8f177c8e 6702 //
2d66e025
MB
6703 return ( left >= 0 && right <= cw &&
6704 top >= 0 && bottom <= ch );
6705 }
6706 else
6707 {
6708 // is the cell partly visible ?
6709 //
6710 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
6711 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
6712 }
6713}
6714
6715
6716// make the specified cell location visible by doing a minimal amount
6717// of scrolling
6718//
6719void wxGrid::MakeCellVisible( int row, int col )
6720{
6721 int i;
60ff3b99 6722 int xpos = -1, ypos = -1;
2d66e025
MB
6723
6724 if ( row >= 0 && row < m_numRows &&
6725 col >= 0 && col < m_numCols )
6726 {
6727 // get the cell rectangle in logical coords
6728 //
6729 wxRect r( CellToRect( row, col ) );
60ff3b99 6730
2d66e025
MB
6731 // convert to device coords
6732 //
6733 int left, top, right, bottom;
6734 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6735 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 6736
2d66e025
MB
6737 int cw, ch;
6738 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 6739
2d66e025 6740 if ( top < 0 )
3f296516 6741 {
2d66e025 6742 ypos = r.GetTop();
3f296516 6743 }
2d66e025
MB
6744 else if ( bottom > ch )
6745 {
6746 int h = r.GetHeight();
6747 ypos = r.GetTop();
6748 for ( i = row-1; i >= 0; i-- )
6749 {
7c1cb261
VZ
6750 int rowHeight = GetRowHeight(i);
6751 if ( h + rowHeight > ch )
6752 break;
2d66e025 6753
7c1cb261
VZ
6754 h += rowHeight;
6755 ypos -= rowHeight;
2d66e025 6756 }
f0102d2a
VZ
6757
6758 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
6759 // have rounding errors (this is important, because if we do, we
6760 // might not scroll at all and some cells won't be redrawn)
6761 ypos += GRID_SCROLL_LINE / 2;
2d66e025
MB
6762 }
6763
6764 if ( left < 0 )
6765 {
6766 xpos = r.GetLeft();
6767 }
6768 else if ( right > cw )
6769 {
6770 int w = r.GetWidth();
6771 xpos = r.GetLeft();
6772 for ( i = col-1; i >= 0; i-- )
6773 {
7c1cb261
VZ
6774 int colWidth = GetColWidth(i);
6775 if ( w + colWidth > cw )
6776 break;
2d66e025 6777
7c1cb261
VZ
6778 w += colWidth;
6779 xpos -= colWidth;
2d66e025 6780 }
f0102d2a
VZ
6781
6782 // see comment for ypos above
6783 xpos += GRID_SCROLL_LINE / 2;
2d66e025
MB
6784 }
6785
6786 if ( xpos != -1 || ypos != -1 )
6787 {
f0102d2a
VZ
6788 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
6789 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
2d66e025
MB
6790 Scroll( xpos, ypos );
6791 AdjustScrollbars();
6792 }
6793 }
6794}
6795
6796
6797//
6798// ------ Grid cursor movement functions
6799//
6800
5c8fc7c1 6801bool wxGrid::MoveCursorUp( bool expandSelection )
2d66e025
MB
6802{
6803 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 6804 m_currentCellCoords.GetRow() >= 0 )
2d66e025 6805 {
f6bcfd97 6806 if ( expandSelection)
d95b0c2b
SN
6807 {
6808 if ( m_selectingKeyboard == wxGridNoCellCoords )
6809 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
6810 if ( m_selectingKeyboard.GetRow() > 0 )
6811 {
6812 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 );
6813 MakeCellVisible( m_selectingKeyboard.GetRow(),
6814 m_selectingKeyboard.GetCol() );
c9097836 6815 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 6816 }
d95b0c2b 6817 }
f6bcfd97 6818 else if ( m_currentCellCoords.GetRow() > 0 )
aa5e1f75
SN
6819 {
6820 ClearSelection();
6821 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
6822 m_currentCellCoords.GetCol() );
d95b0c2b
SN
6823 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
6824 m_currentCellCoords.GetCol() );
aa5e1f75 6825 }
f6bcfd97
BP
6826 else
6827 return FALSE;
8f177c8e 6828 return TRUE;
f85afd4e 6829 }
2d66e025
MB
6830
6831 return FALSE;
6832}
6833
6834
5c8fc7c1 6835bool wxGrid::MoveCursorDown( bool expandSelection )
2d66e025 6836{
2d66e025 6837 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 6838 m_currentCellCoords.GetRow() < m_numRows )
f85afd4e 6839 {
5c8fc7c1 6840 if ( expandSelection )
d95b0c2b
SN
6841 {
6842 if ( m_selectingKeyboard == wxGridNoCellCoords )
6843 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
6844 if ( m_selectingKeyboard.GetRow() < m_numRows-1 )
6845 {
6846 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 );
6847 MakeCellVisible( m_selectingKeyboard.GetRow(),
6848 m_selectingKeyboard.GetCol() );
c9097836 6849 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 6850 }
d95b0c2b 6851 }
f6bcfd97 6852 else if ( m_currentCellCoords.GetRow() < m_numRows - 1 )
aa5e1f75
SN
6853 {
6854 ClearSelection();
6855 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
6856 m_currentCellCoords.GetCol() );
d95b0c2b
SN
6857 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
6858 m_currentCellCoords.GetCol() );
aa5e1f75 6859 }
f6bcfd97
BP
6860 else
6861 return FALSE;
2d66e025 6862 return TRUE;
f85afd4e 6863 }
2d66e025
MB
6864
6865 return FALSE;
f85afd4e
MB
6866}
6867
2d66e025 6868
5c8fc7c1 6869bool wxGrid::MoveCursorLeft( bool expandSelection )
f85afd4e 6870{
2d66e025 6871 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 6872 m_currentCellCoords.GetCol() >= 0 )
2d66e025 6873 {
5c8fc7c1 6874 if ( expandSelection )
d95b0c2b
SN
6875 {
6876 if ( m_selectingKeyboard == wxGridNoCellCoords )
6877 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
6878 if ( m_selectingKeyboard.GetCol() > 0 )
6879 {
6880 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 );
6881 MakeCellVisible( m_selectingKeyboard.GetRow(),
6882 m_selectingKeyboard.GetCol() );
c9097836 6883 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 6884 }
d95b0c2b 6885 }
f6bcfd97 6886 else if ( m_currentCellCoords.GetCol() > 0 )
aa5e1f75
SN
6887 {
6888 ClearSelection();
6889 MakeCellVisible( m_currentCellCoords.GetRow(),
6890 m_currentCellCoords.GetCol() - 1 );
d95b0c2b
SN
6891 SetCurrentCell( m_currentCellCoords.GetRow(),
6892 m_currentCellCoords.GetCol() - 1 );
aa5e1f75 6893 }
f6bcfd97
BP
6894 else
6895 return FALSE;
2d66e025
MB
6896 return TRUE;
6897 }
6898
6899 return FALSE;
6900}
6901
6902
5c8fc7c1 6903bool wxGrid::MoveCursorRight( bool expandSelection )
2d66e025
MB
6904{
6905 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 6906 m_currentCellCoords.GetCol() < m_numCols )
f85afd4e 6907 {
5c8fc7c1 6908 if ( expandSelection )
d95b0c2b
SN
6909 {
6910 if ( m_selectingKeyboard == wxGridNoCellCoords )
6911 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
6912 if ( m_selectingKeyboard.GetCol() < m_numCols - 1 )
6913 {
6914 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 );
6915 MakeCellVisible( m_selectingKeyboard.GetRow(),
6916 m_selectingKeyboard.GetCol() );
c9097836 6917 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 6918 }
d95b0c2b 6919 }
f6bcfd97 6920 else if ( m_currentCellCoords.GetCol() < m_numCols - 1 )
aa5e1f75
SN
6921 {
6922 ClearSelection();
6923 MakeCellVisible( m_currentCellCoords.GetRow(),
6924 m_currentCellCoords.GetCol() + 1 );
6925 SetCurrentCell( m_currentCellCoords.GetRow(),
d95b0c2b 6926 m_currentCellCoords.GetCol() + 1 );
aa5e1f75 6927 }
f6bcfd97
BP
6928 else
6929 return FALSE;
2d66e025 6930 return TRUE;
f85afd4e 6931 }
8f177c8e 6932
2d66e025
MB
6933 return FALSE;
6934}
6935
6936
6937bool wxGrid::MovePageUp()
6938{
6939 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 6940
2d66e025
MB
6941 int row = m_currentCellCoords.GetRow();
6942 if ( row > 0 )
f85afd4e 6943 {
2d66e025
MB
6944 int cw, ch;
6945 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 6946
7c1cb261 6947 int y = GetRowTop(row);
2d66e025
MB
6948 int newRow = YToRow( y - ch + 1 );
6949 if ( newRow == -1 )
6950 {
6951 newRow = 0;
6952 }
60ff3b99 6953 else if ( newRow == row )
2d66e025
MB
6954 {
6955 newRow = row - 1;
6956 }
8f177c8e 6957
2d66e025
MB
6958 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
6959 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 6960
f85afd4e
MB
6961 return TRUE;
6962 }
2d66e025
MB
6963
6964 return FALSE;
6965}
6966
6967bool wxGrid::MovePageDown()
6968{
6969 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 6970
2d66e025
MB
6971 int row = m_currentCellCoords.GetRow();
6972 if ( row < m_numRows )
f85afd4e 6973 {
2d66e025
MB
6974 int cw, ch;
6975 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 6976
7c1cb261 6977 int y = GetRowTop(row);
2d66e025
MB
6978 int newRow = YToRow( y + ch );
6979 if ( newRow == -1 )
6980 {
6981 newRow = m_numRows - 1;
6982 }
60ff3b99 6983 else if ( newRow == row )
2d66e025
MB
6984 {
6985 newRow = row + 1;
6986 }
6987
6988 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
6989 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 6990
2d66e025 6991 return TRUE;
f85afd4e 6992 }
2d66e025
MB
6993
6994 return FALSE;
f85afd4e 6995}
8f177c8e 6996
5c8fc7c1 6997bool wxGrid::MoveCursorUpBlock( bool expandSelection )
2d66e025
MB
6998{
6999 if ( m_table &&
7000 m_currentCellCoords != wxGridNoCellCoords &&
7001 m_currentCellCoords.GetRow() > 0 )
7002 {
7003 int row = m_currentCellCoords.GetRow();
7004 int col = m_currentCellCoords.GetCol();
7005
7006 if ( m_table->IsEmptyCell(row, col) )
7007 {
7008 // starting in an empty cell: find the next block of
7009 // non-empty cells
7010 //
7011 while ( row > 0 )
7012 {
7013 row-- ;
7014 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7015 }
7016 }
7017 else if ( m_table->IsEmptyCell(row-1, col) )
7018 {
7019 // starting at the top of a block: find the next block
7020 //
7021 row--;
7022 while ( row > 0 )
7023 {
7024 row-- ;
7025 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7026 }
7027 }
7028 else
7029 {
7030 // starting within a block: find the top of the block
7031 //
7032 while ( row > 0 )
7033 {
7034 row-- ;
7035 if ( m_table->IsEmptyCell(row, col) )
7036 {
7037 row++ ;
7038 break;
7039 }
7040 }
7041 }
f85afd4e 7042
2d66e025 7043 MakeCellVisible( row, col );
5c8fc7c1 7044 if ( expandSelection )
d95b0c2b
SN
7045 {
7046 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 7047 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
7048 }
7049 else
aa5e1f75
SN
7050 {
7051 ClearSelection();
7052 SetCurrentCell( row, col );
7053 }
2d66e025
MB
7054 return TRUE;
7055 }
f85afd4e 7056
2d66e025
MB
7057 return FALSE;
7058}
f85afd4e 7059
5c8fc7c1 7060bool wxGrid::MoveCursorDownBlock( bool expandSelection )
f85afd4e 7061{
2d66e025
MB
7062 if ( m_table &&
7063 m_currentCellCoords != wxGridNoCellCoords &&
7064 m_currentCellCoords.GetRow() < m_numRows-1 )
f85afd4e 7065 {
2d66e025
MB
7066 int row = m_currentCellCoords.GetRow();
7067 int col = m_currentCellCoords.GetCol();
7068
7069 if ( m_table->IsEmptyCell(row, col) )
7070 {
7071 // starting in an empty cell: find the next block of
7072 // non-empty cells
7073 //
7074 while ( row < m_numRows-1 )
7075 {
7076 row++ ;
7077 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7078 }
7079 }
7080 else if ( m_table->IsEmptyCell(row+1, col) )
7081 {
7082 // starting at the bottom of a block: find the next block
7083 //
7084 row++;
7085 while ( row < m_numRows-1 )
7086 {
7087 row++ ;
7088 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7089 }
7090 }
7091 else
7092 {
7093 // starting within a block: find the bottom of the block
7094 //
7095 while ( row < m_numRows-1 )
7096 {
7097 row++ ;
7098 if ( m_table->IsEmptyCell(row, col) )
7099 {
7100 row-- ;
7101 break;
7102 }
7103 }
7104 }
7105
7106 MakeCellVisible( row, col );
5c8fc7c1 7107 if ( expandSelection )
d95b0c2b
SN
7108 {
7109 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 7110 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
7111 }
7112 else
aa5e1f75
SN
7113 {
7114 ClearSelection();
7115 SetCurrentCell( row, col );
7116 }
2d66e025
MB
7117
7118 return TRUE;
f85afd4e 7119 }
f85afd4e 7120
2d66e025
MB
7121 return FALSE;
7122}
f85afd4e 7123
5c8fc7c1 7124bool wxGrid::MoveCursorLeftBlock( bool expandSelection )
f85afd4e 7125{
2d66e025
MB
7126 if ( m_table &&
7127 m_currentCellCoords != wxGridNoCellCoords &&
7128 m_currentCellCoords.GetCol() > 0 )
f85afd4e 7129 {
2d66e025
MB
7130 int row = m_currentCellCoords.GetRow();
7131 int col = m_currentCellCoords.GetCol();
7132
7133 if ( m_table->IsEmptyCell(row, col) )
7134 {
7135 // starting in an empty cell: find the next block of
7136 // non-empty cells
7137 //
7138 while ( col > 0 )
7139 {
7140 col-- ;
7141 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7142 }
7143 }
7144 else if ( m_table->IsEmptyCell(row, col-1) )
7145 {
7146 // starting at the left of a block: find the next block
7147 //
7148 col--;
7149 while ( col > 0 )
7150 {
7151 col-- ;
7152 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7153 }
7154 }
7155 else
7156 {
7157 // starting within a block: find the left of the block
7158 //
7159 while ( col > 0 )
7160 {
7161 col-- ;
7162 if ( m_table->IsEmptyCell(row, col) )
7163 {
7164 col++ ;
7165 break;
7166 }
7167 }
7168 }
f85afd4e 7169
2d66e025 7170 MakeCellVisible( row, col );
5c8fc7c1 7171 if ( expandSelection )
d95b0c2b
SN
7172 {
7173 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 7174 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
7175 }
7176 else
aa5e1f75
SN
7177 {
7178 ClearSelection();
7179 SetCurrentCell( row, col );
7180 }
8f177c8e 7181
2d66e025 7182 return TRUE;
f85afd4e 7183 }
2d66e025
MB
7184
7185 return FALSE;
f85afd4e
MB
7186}
7187
5c8fc7c1 7188bool wxGrid::MoveCursorRightBlock( bool expandSelection )
f85afd4e 7189{
2d66e025
MB
7190 if ( m_table &&
7191 m_currentCellCoords != wxGridNoCellCoords &&
7192 m_currentCellCoords.GetCol() < m_numCols-1 )
f85afd4e 7193 {
2d66e025
MB
7194 int row = m_currentCellCoords.GetRow();
7195 int col = m_currentCellCoords.GetCol();
8f177c8e 7196
2d66e025
MB
7197 if ( m_table->IsEmptyCell(row, col) )
7198 {
7199 // starting in an empty cell: find the next block of
7200 // non-empty cells
7201 //
7202 while ( col < m_numCols-1 )
7203 {
7204 col++ ;
7205 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7206 }
7207 }
7208 else if ( m_table->IsEmptyCell(row, col+1) )
7209 {
7210 // starting at the right of a block: find the next block
7211 //
7212 col++;
7213 while ( col < m_numCols-1 )
7214 {
7215 col++ ;
7216 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7217 }
7218 }
7219 else
7220 {
7221 // starting within a block: find the right of the block
7222 //
7223 while ( col < m_numCols-1 )
7224 {
7225 col++ ;
7226 if ( m_table->IsEmptyCell(row, col) )
7227 {
7228 col-- ;
7229 break;
7230 }
7231 }
7232 }
8f177c8e 7233
2d66e025 7234 MakeCellVisible( row, col );
5c8fc7c1 7235 if ( expandSelection )
d95b0c2b
SN
7236 {
7237 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 7238 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
7239 }
7240 else
aa5e1f75
SN
7241 {
7242 ClearSelection();
7243 SetCurrentCell( row, col );
7244 }
f85afd4e 7245
2d66e025 7246 return TRUE;
f85afd4e 7247 }
2d66e025
MB
7248
7249 return FALSE;
f85afd4e
MB
7250}
7251
7252
2d66e025 7253
f85afd4e 7254//
2d66e025 7255// ------ Label values and formatting
f85afd4e
MB
7256//
7257
7258void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
7259{
7260 *horiz = m_rowLabelHorizAlign;
7261 *vert = m_rowLabelVertAlign;
7262}
7263
7264void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
7265{
7266 *horiz = m_colLabelHorizAlign;
7267 *vert = m_colLabelVertAlign;
7268}
7269
7270wxString wxGrid::GetRowLabelValue( int row )
7271{
7272 if ( m_table )
7273 {
7274 return m_table->GetRowLabelValue( row );
7275 }
7276 else
7277 {
7278 wxString s;
7279 s << row;
7280 return s;
7281 }
7282}
7283
7284wxString wxGrid::GetColLabelValue( int col )
7285{
7286 if ( m_table )
7287 {
7288 return m_table->GetColLabelValue( col );
7289 }
7290 else
7291 {
7292 wxString s;
7293 s << col;
7294 return s;
7295 }
7296}
7297
2e8cd977 7298
f85afd4e
MB
7299void wxGrid::SetRowLabelSize( int width )
7300{
2e8cd977
MB
7301 width = wxMax( width, 0 );
7302 if ( width != m_rowLabelWidth )
7303 {
2e8cd977
MB
7304 if ( width == 0 )
7305 {
7306 m_rowLabelWin->Show( FALSE );
7807d81c 7307 m_cornerLabelWin->Show( FALSE );
2e8cd977 7308 }
7807d81c 7309 else if ( m_rowLabelWidth == 0 )
2e8cd977 7310 {
7807d81c
MB
7311 m_rowLabelWin->Show( TRUE );
7312 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
2e8cd977 7313 }
b99be8fb 7314
2e8cd977 7315 m_rowLabelWidth = width;
7807d81c
MB
7316 CalcWindowSizes();
7317 Refresh( TRUE );
2e8cd977 7318 }
f85afd4e
MB
7319}
7320
2e8cd977 7321
f85afd4e
MB
7322void wxGrid::SetColLabelSize( int height )
7323{
7807d81c 7324 height = wxMax( height, 0 );
2e8cd977
MB
7325 if ( height != m_colLabelHeight )
7326 {
2e8cd977
MB
7327 if ( height == 0 )
7328 {
2e8cd977 7329 m_colLabelWin->Show( FALSE );
7807d81c 7330 m_cornerLabelWin->Show( FALSE );
2e8cd977 7331 }
7807d81c 7332 else if ( m_colLabelHeight == 0 )
2e8cd977 7333 {
7807d81c
MB
7334 m_colLabelWin->Show( TRUE );
7335 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
2e8cd977 7336 }
7807d81c 7337
2e8cd977 7338 m_colLabelHeight = height;
7807d81c
MB
7339 CalcWindowSizes();
7340 Refresh( TRUE );
2e8cd977 7341 }
f85afd4e
MB
7342}
7343
2e8cd977 7344
f85afd4e
MB
7345void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
7346{
2d66e025
MB
7347 if ( m_labelBackgroundColour != colour )
7348 {
7349 m_labelBackgroundColour = colour;
7350 m_rowLabelWin->SetBackgroundColour( colour );
7351 m_colLabelWin->SetBackgroundColour( colour );
7352 m_cornerLabelWin->SetBackgroundColour( colour );
7353
7354 if ( !GetBatchCount() )
7355 {
7356 m_rowLabelWin->Refresh();
7357 m_colLabelWin->Refresh();
7358 m_cornerLabelWin->Refresh();
7359 }
7360 }
f85afd4e
MB
7361}
7362
7363void wxGrid::SetLabelTextColour( const wxColour& colour )
7364{
2d66e025
MB
7365 if ( m_labelTextColour != colour )
7366 {
7367 m_labelTextColour = colour;
7368 if ( !GetBatchCount() )
7369 {
7370 m_rowLabelWin->Refresh();
7371 m_colLabelWin->Refresh();
7372 }
7373 }
f85afd4e
MB
7374}
7375
7376void wxGrid::SetLabelFont( const wxFont& font )
7377{
7378 m_labelFont = font;
2d66e025
MB
7379 if ( !GetBatchCount() )
7380 {
7381 m_rowLabelWin->Refresh();
7382 m_colLabelWin->Refresh();
7383 }
f85afd4e
MB
7384}
7385
7386void wxGrid::SetRowLabelAlignment( int horiz, int vert )
7387{
4c7277db
MB
7388 // allow old (incorrect) defs to be used
7389 switch ( horiz )
7390 {
7391 case wxLEFT: horiz = wxALIGN_LEFT; break;
7392 case wxRIGHT: horiz = wxALIGN_RIGHT; break;
7393 case wxCENTRE: horiz = wxALIGN_CENTRE; break;
7394 }
84912ef8 7395
4c7277db
MB
7396 switch ( vert )
7397 {
7398 case wxTOP: vert = wxALIGN_TOP; break;
7399 case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
7400 case wxCENTRE: vert = wxALIGN_CENTRE; break;
7401 }
84912ef8 7402
4c7277db 7403 if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
f85afd4e
MB
7404 {
7405 m_rowLabelHorizAlign = horiz;
7406 }
8f177c8e 7407
4c7277db 7408 if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
f85afd4e
MB
7409 {
7410 m_rowLabelVertAlign = vert;
7411 }
7412
2d66e025
MB
7413 if ( !GetBatchCount() )
7414 {
7415 m_rowLabelWin->Refresh();
60ff3b99 7416 }
f85afd4e
MB
7417}
7418
7419void wxGrid::SetColLabelAlignment( int horiz, int vert )
7420{
4c7277db
MB
7421 // allow old (incorrect) defs to be used
7422 switch ( horiz )
7423 {
7424 case wxLEFT: horiz = wxALIGN_LEFT; break;
7425 case wxRIGHT: horiz = wxALIGN_RIGHT; break;
7426 case wxCENTRE: horiz = wxALIGN_CENTRE; break;
7427 }
84912ef8 7428
4c7277db
MB
7429 switch ( vert )
7430 {
7431 case wxTOP: vert = wxALIGN_TOP; break;
7432 case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
7433 case wxCENTRE: vert = wxALIGN_CENTRE; break;
7434 }
84912ef8 7435
4c7277db 7436 if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
f85afd4e
MB
7437 {
7438 m_colLabelHorizAlign = horiz;
7439 }
8f177c8e 7440
4c7277db 7441 if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
f85afd4e
MB
7442 {
7443 m_colLabelVertAlign = vert;
7444 }
7445
2d66e025
MB
7446 if ( !GetBatchCount() )
7447 {
2d66e025 7448 m_colLabelWin->Refresh();
60ff3b99 7449 }
f85afd4e
MB
7450}
7451
7452void wxGrid::SetRowLabelValue( int row, const wxString& s )
7453{
7454 if ( m_table )
7455 {
7456 m_table->SetRowLabelValue( row, s );
2d66e025
MB
7457 if ( !GetBatchCount() )
7458 {
70c7a608
SN
7459 wxRect rect = CellToRect( row, 0);
7460 if ( rect.height > 0 )
7461 {
cb309039 7462 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
b1944ebc 7463 rect.x = 0;
70c7a608
SN
7464 rect.width = m_rowLabelWidth;
7465 m_rowLabelWin->Refresh( TRUE, &rect );
7466 }
2d66e025 7467 }
f85afd4e
MB
7468 }
7469}
7470
7471void wxGrid::SetColLabelValue( int col, const wxString& s )
7472{
7473 if ( m_table )
7474 {
7475 m_table->SetColLabelValue( col, s );
2d66e025
MB
7476 if ( !GetBatchCount() )
7477 {
70c7a608
SN
7478 wxRect rect = CellToRect( 0, col );
7479 if ( rect.width > 0 )
7480 {
cb309039 7481 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
b1944ebc 7482 rect.y = 0;
70c7a608
SN
7483 rect.height = m_colLabelHeight;
7484 m_colLabelWin->Refresh( TRUE, &rect );
7485 }
2d66e025 7486 }
f85afd4e
MB
7487 }
7488}
7489
7490void wxGrid::SetGridLineColour( const wxColour& colour )
7491{
2d66e025
MB
7492 if ( m_gridLineColour != colour )
7493 {
7494 m_gridLineColour = colour;
60ff3b99 7495
2d66e025
MB
7496 wxClientDC dc( m_gridWin );
7497 PrepareDC( dc );
c6a51dcd 7498 DrawAllGridLines( dc, wxRegion() );
2d66e025 7499 }
f85afd4e
MB
7500}
7501
f6bcfd97
BP
7502
7503void wxGrid::SetCellHighlightColour( const wxColour& colour )
7504{
7505 if ( m_cellHighlightColour != colour )
7506 {
7507 m_cellHighlightColour = colour;
7508
7509 wxClientDC dc( m_gridWin );
7510 PrepareDC( dc );
7511 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
7512 DrawCellHighlight(dc, attr);
7513 attr->DecRef();
7514 }
7515}
7516
f85afd4e
MB
7517void wxGrid::EnableGridLines( bool enable )
7518{
7519 if ( enable != m_gridLinesEnabled )
7520 {
7521 m_gridLinesEnabled = enable;
2d66e025
MB
7522
7523 if ( !GetBatchCount() )
7524 {
7525 if ( enable )
7526 {
7527 wxClientDC dc( m_gridWin );
7528 PrepareDC( dc );
c6a51dcd 7529 DrawAllGridLines( dc, wxRegion() );
2d66e025
MB
7530 }
7531 else
7532 {
7533 m_gridWin->Refresh();
7534 }
7535 }
f85afd4e
MB
7536 }
7537}
7538
7539
7540int wxGrid::GetDefaultRowSize()
7541{
7542 return m_defaultRowHeight;
7543}
7544
7545int wxGrid::GetRowSize( int row )
7546{
b99be8fb
VZ
7547 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
7548
7c1cb261 7549 return GetRowHeight(row);
f85afd4e
MB
7550}
7551
7552int wxGrid::GetDefaultColSize()
7553{
7554 return m_defaultColWidth;
7555}
7556
7557int wxGrid::GetColSize( int col )
7558{
b99be8fb
VZ
7559 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
7560
7c1cb261 7561 return GetColWidth(col);
f85afd4e
MB
7562}
7563
2e9a6788
VZ
7564// ============================================================================
7565// access to the grid attributes: each of them has a default value in the grid
7566// itself and may be overidden on a per-cell basis
7567// ============================================================================
7568
7569// ----------------------------------------------------------------------------
7570// setting default attributes
7571// ----------------------------------------------------------------------------
7572
7573void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
7574{
2796cce3 7575 m_defaultCellAttr->SetBackgroundColour(col);
c916e13b
RR
7576#ifdef __WXGTK__
7577 m_gridWin->SetBackgroundColour(col);
7578#endif
2e9a6788
VZ
7579}
7580
7581void wxGrid::SetDefaultCellTextColour( const wxColour& col )
7582{
2796cce3 7583 m_defaultCellAttr->SetTextColour(col);
2e9a6788
VZ
7584}
7585
7586void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
7587{
2796cce3 7588 m_defaultCellAttr->SetAlignment(horiz, vert);
2e9a6788
VZ
7589}
7590
7591void wxGrid::SetDefaultCellFont( const wxFont& font )
7592{
2796cce3
RD
7593 m_defaultCellAttr->SetFont(font);
7594}
7595
0ba143c9
RD
7596void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
7597{
7598 m_defaultCellAttr->SetRenderer(renderer);
7599}
2e9a6788 7600
0ba143c9
RD
7601void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
7602{
7603 m_defaultCellAttr->SetEditor(editor);
7604}
9b4aede2 7605
2e9a6788
VZ
7606// ----------------------------------------------------------------------------
7607// access to the default attrbiutes
7608// ----------------------------------------------------------------------------
7609
f85afd4e
MB
7610wxColour wxGrid::GetDefaultCellBackgroundColour()
7611{
2796cce3 7612 return m_defaultCellAttr->GetBackgroundColour();
f85afd4e
MB
7613}
7614
2e9a6788
VZ
7615wxColour wxGrid::GetDefaultCellTextColour()
7616{
2796cce3 7617 return m_defaultCellAttr->GetTextColour();
2e9a6788
VZ
7618}
7619
7620wxFont wxGrid::GetDefaultCellFont()
7621{
2796cce3 7622 return m_defaultCellAttr->GetFont();
2e9a6788
VZ
7623}
7624
7625void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
7626{
2796cce3 7627 m_defaultCellAttr->GetAlignment(horiz, vert);
2e9a6788
VZ
7628}
7629
0ba143c9
RD
7630wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
7631{
0b190b0f 7632 return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
0ba143c9 7633}
ab79958a 7634
0ba143c9
RD
7635wxGridCellEditor *wxGrid::GetDefaultEditor() const
7636{
28a77bc4 7637 return m_defaultCellAttr->GetEditor(NULL,0,0);
0ba143c9 7638}
9b4aede2 7639
2e9a6788
VZ
7640// ----------------------------------------------------------------------------
7641// access to cell attributes
7642// ----------------------------------------------------------------------------
7643
b99be8fb 7644wxColour wxGrid::GetCellBackgroundColour(int row, int col)
f85afd4e 7645{
0a976765 7646 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 7647 wxColour colour = attr->GetBackgroundColour();
39bcce60 7648 attr->DecRef();
b99be8fb 7649 return colour;
f85afd4e
MB
7650}
7651
b99be8fb 7652wxColour wxGrid::GetCellTextColour( int row, int col )
f85afd4e 7653{
0a976765 7654 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 7655 wxColour colour = attr->GetTextColour();
39bcce60 7656 attr->DecRef();
b99be8fb 7657 return colour;
f85afd4e
MB
7658}
7659
b99be8fb 7660wxFont wxGrid::GetCellFont( int row, int col )
f85afd4e 7661{
0a976765 7662 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 7663 wxFont font = attr->GetFont();
39bcce60 7664 attr->DecRef();
b99be8fb 7665 return font;
f85afd4e
MB
7666}
7667
b99be8fb 7668void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
f85afd4e 7669{
0a976765 7670 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 7671 attr->GetAlignment(horiz, vert);
39bcce60 7672 attr->DecRef();
2e9a6788
VZ
7673}
7674
2796cce3
RD
7675wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
7676{
7677 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 7678 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
2796cce3 7679 attr->DecRef();
0b190b0f 7680
2796cce3
RD
7681 return renderer;
7682}
7683
9b4aede2
RD
7684wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
7685{
7686 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 7687 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
9b4aede2 7688 attr->DecRef();
0b190b0f 7689
9b4aede2
RD
7690 return editor;
7691}
7692
283b7808
VZ
7693bool wxGrid::IsReadOnly(int row, int col) const
7694{
7695 wxGridCellAttr* attr = GetCellAttr(row, col);
7696 bool isReadOnly = attr->IsReadOnly();
7697 attr->DecRef();
7698 return isReadOnly;
7699}
7700
2e9a6788 7701// ----------------------------------------------------------------------------
758cbedf 7702// attribute support: cache, automatic provider creation, ...
2e9a6788
VZ
7703// ----------------------------------------------------------------------------
7704
7705bool wxGrid::CanHaveAttributes()
7706{
7707 if ( !m_table )
7708 {
7709 return FALSE;
7710 }
7711
f2d76237 7712 return m_table->CanHaveAttributes();
2e9a6788
VZ
7713}
7714
0a976765
VZ
7715void wxGrid::ClearAttrCache()
7716{
7717 if ( m_attrCache.row != -1 )
7718 {
39bcce60 7719 wxSafeDecRef(m_attrCache.attr);
0a976765
VZ
7720 m_attrCache.row = -1;
7721 }
7722}
7723
7724void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
7725{
7726 wxGrid *self = (wxGrid *)this; // const_cast
7727
7728 self->ClearAttrCache();
7729 self->m_attrCache.row = row;
7730 self->m_attrCache.col = col;
7731 self->m_attrCache.attr = attr;
39bcce60 7732 wxSafeIncRef(attr);
0a976765
VZ
7733}
7734
7735bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
7736{
7737 if ( row == m_attrCache.row && col == m_attrCache.col )
7738 {
7739 *attr = m_attrCache.attr;
39bcce60 7740 wxSafeIncRef(m_attrCache.attr);
0a976765
VZ
7741
7742#ifdef DEBUG_ATTR_CACHE
7743 gs_nAttrCacheHits++;
7744#endif
7745
7746 return TRUE;
7747 }
7748 else
7749 {
7750#ifdef DEBUG_ATTR_CACHE
7751 gs_nAttrCacheMisses++;
7752#endif
7753 return FALSE;
7754 }
7755}
7756
2e9a6788
VZ
7757wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
7758{
0a976765
VZ
7759 wxGridCellAttr *attr;
7760 if ( !LookupAttr(row, col, &attr) )
2e9a6788 7761 {
0a976765
VZ
7762 attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
7763 CacheAttr(row, col, attr);
7764 }
508011ce
VZ
7765 if (attr)
7766 {
2796cce3 7767 attr->SetDefAttr(m_defaultCellAttr);
508011ce
VZ
7768 }
7769 else
7770 {
2796cce3
RD
7771 attr = m_defaultCellAttr;
7772 attr->IncRef();
7773 }
2e9a6788 7774
0a976765
VZ
7775 return attr;
7776}
7777
7778wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
7779{
7780 wxGridCellAttr *attr;
7781 if ( !LookupAttr(row, col, &attr) || !attr )
7782 {
7783 wxASSERT_MSG( m_table,
f6bcfd97 7784 _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") );
0a976765
VZ
7785
7786 attr = m_table->GetAttr(row, col);
7787 if ( !attr )
7788 {
7789 attr = new wxGridCellAttr;
7790
7791 // artificially inc the ref count to match DecRef() in caller
7792 attr->IncRef();
7793
7794 m_table->SetAttr(attr, row, col);
7795 }
2e9a6788 7796
0a976765 7797 CacheAttr(row, col, attr);
2e9a6788 7798 }
2796cce3 7799 attr->SetDefAttr(m_defaultCellAttr);
2e9a6788
VZ
7800 return attr;
7801}
7802
0b190b0f
VZ
7803// ----------------------------------------------------------------------------
7804// setting column attributes (wrappers around SetColAttr)
7805// ----------------------------------------------------------------------------
7806
7807void wxGrid::SetColFormatBool(int col)
7808{
7809 SetColFormatCustom(col, wxGRID_VALUE_BOOL);
7810}
7811
7812void wxGrid::SetColFormatNumber(int col)
7813{
7814 SetColFormatCustom(col, wxGRID_VALUE_NUMBER);
7815}
7816
7817void wxGrid::SetColFormatFloat(int col, int width, int precision)
7818{
7819 wxString typeName = wxGRID_VALUE_FLOAT;
7820 if ( (width != -1) || (precision != -1) )
7821 {
7822 typeName << _T(':') << width << _T(',') << precision;
7823 }
7824
7825 SetColFormatCustom(col, typeName);
7826}
7827
7828void wxGrid::SetColFormatCustom(int col, const wxString& typeName)
7829{
7830 wxGridCellAttr *attr = new wxGridCellAttr;
7831 wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName);
7832 attr->SetRenderer(renderer);
7833
7834 SetColAttr(col, attr);
7835}
7836
758cbedf
VZ
7837// ----------------------------------------------------------------------------
7838// setting cell attributes: this is forwarded to the table
7839// ----------------------------------------------------------------------------
7840
7841void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
7842{
7843 if ( CanHaveAttributes() )
7844 {
7845 m_table->SetRowAttr(attr, row);
7846 }
7847 else
7848 {
39bcce60 7849 wxSafeDecRef(attr);
758cbedf
VZ
7850 }
7851}
7852
7853void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
7854{
7855 if ( CanHaveAttributes() )
7856 {
7857 m_table->SetColAttr(attr, col);
7858 }
7859 else
7860 {
39bcce60 7861 wxSafeDecRef(attr);
758cbedf
VZ
7862 }
7863}
7864
2e9a6788
VZ
7865void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
7866{
7867 if ( CanHaveAttributes() )
7868 {
0a976765 7869 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
7870 attr->SetBackgroundColour(colour);
7871 attr->DecRef();
7872 }
7873}
7874
7875void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
7876{
7877 if ( CanHaveAttributes() )
7878 {
0a976765 7879 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
7880 attr->SetTextColour(colour);
7881 attr->DecRef();
7882 }
7883}
7884
7885void wxGrid::SetCellFont( int row, int col, const wxFont& font )
7886{
7887 if ( CanHaveAttributes() )
7888 {
0a976765 7889 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
7890 attr->SetFont(font);
7891 attr->DecRef();
7892 }
7893}
7894
7895void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
7896{
7897 if ( CanHaveAttributes() )
7898 {
0a976765 7899 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
7900 attr->SetAlignment(horiz, vert);
7901 attr->DecRef();
ab79958a
VZ
7902 }
7903}
7904
7905void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
7906{
7907 if ( CanHaveAttributes() )
7908 {
0a976765 7909 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
ab79958a
VZ
7910 attr->SetRenderer(renderer);
7911 attr->DecRef();
9b4aede2
RD
7912 }
7913}
7914
7915void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
7916{
7917 if ( CanHaveAttributes() )
7918 {
7919 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7920 attr->SetEditor(editor);
7921 attr->DecRef();
283b7808
VZ
7922 }
7923}
7924
7925void wxGrid::SetReadOnly(int row, int col, bool isReadOnly)
7926{
7927 if ( CanHaveAttributes() )
7928 {
7929 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7930 attr->SetReadOnly(isReadOnly);
7931 attr->DecRef();
2e9a6788 7932 }
f85afd4e
MB
7933}
7934
f2d76237
RD
7935// ----------------------------------------------------------------------------
7936// Data type registration
7937// ----------------------------------------------------------------------------
7938
7939void wxGrid::RegisterDataType(const wxString& typeName,
7940 wxGridCellRenderer* renderer,
7941 wxGridCellEditor* editor)
7942{
7943 m_typeRegistry->RegisterDataType(typeName, renderer, editor);
7944}
7945
7946
99306db2 7947wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const
f2d76237
RD
7948{
7949 wxString typeName = m_table->GetTypeName(row, col);
7950 return GetDefaultEditorForType(typeName);
7951}
7952
99306db2 7953wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const
f2d76237
RD
7954{
7955 wxString typeName = m_table->GetTypeName(row, col);
7956 return GetDefaultRendererForType(typeName);
7957}
7958
99306db2
VZ
7959wxGridCellEditor*
7960wxGrid::GetDefaultEditorForType(const wxString& typeName) const
f2d76237 7961{
c4608a8a 7962 int index = m_typeRegistry->FindOrCloneDataType(typeName);
0b190b0f
VZ
7963 if ( index == wxNOT_FOUND )
7964 {
7965 wxFAIL_MSG(wxT("Unknown data type name"));
7966
f2d76237
RD
7967 return NULL;
7968 }
0b190b0f 7969
f2d76237
RD
7970 return m_typeRegistry->GetEditor(index);
7971}
7972
99306db2
VZ
7973wxGridCellRenderer*
7974wxGrid::GetDefaultRendererForType(const wxString& typeName) const
f2d76237 7975{
c4608a8a 7976 int index = m_typeRegistry->FindOrCloneDataType(typeName);
0b190b0f
VZ
7977 if ( index == wxNOT_FOUND )
7978 {
c4608a8a 7979 wxFAIL_MSG(wxT("Unknown data type name"));
0b190b0f 7980
c4608a8a 7981 return NULL;
e72b4213 7982 }
0b190b0f 7983
c4608a8a 7984 return m_typeRegistry->GetRenderer(index);
f2d76237
RD
7985}
7986
7987
2e9a6788
VZ
7988// ----------------------------------------------------------------------------
7989// row/col size
7990// ----------------------------------------------------------------------------
7991
6e8524b1
MB
7992void wxGrid::EnableDragRowSize( bool enable )
7993{
7994 m_canDragRowSize = enable;
7995}
7996
7997
7998void wxGrid::EnableDragColSize( bool enable )
7999{
8000 m_canDragColSize = enable;
8001}
8002
4cfa5de6
RD
8003void wxGrid::EnableDragGridSize( bool enable )
8004{
8005 m_canDragGridSize = enable;
8006}
8007
6e8524b1 8008
f85afd4e
MB
8009void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
8010{
8011 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
8012
8013 if ( resizeExistingRows )
8014 {
7c1cb261 8015 InitRowHeights();
faec5a43
SN
8016 if ( !GetBatchCount() )
8017 CalcDimensions();
f85afd4e
MB
8018 }
8019}
8020
8021void wxGrid::SetRowSize( int row, int height )
8022{
b99be8fb 8023 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
60ff3b99 8024
7c1cb261
VZ
8025 if ( m_rowHeights.IsEmpty() )
8026 {
8027 // need to really create the array
8028 InitRowHeights();
8029 }
60ff3b99 8030
b99be8fb
VZ
8031 int h = wxMax( 0, height );
8032 int diff = h - m_rowHeights[row];
60ff3b99 8033
b99be8fb 8034 m_rowHeights[row] = h;
7c1cb261 8035 int i;
b99be8fb 8036 for ( i = row; i < m_numRows; i++ )
f85afd4e 8037 {
b99be8fb 8038 m_rowBottoms[i] += diff;
f85afd4e 8039 }
faec5a43
SN
8040 if ( !GetBatchCount() )
8041 CalcDimensions();
f85afd4e
MB
8042}
8043
8044void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
8045{
8046 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
8047
8048 if ( resizeExistingCols )
8049 {
7c1cb261 8050 InitColWidths();
faec5a43
SN
8051 if ( !GetBatchCount() )
8052 CalcDimensions();
f85afd4e
MB
8053 }
8054}
8055
8056void wxGrid::SetColSize( int col, int width )
8057{
b99be8fb 8058 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
60ff3b99 8059
43947979
VZ
8060 // should we check that it's bigger than GetColMinimalWidth(col) here?
8061
7c1cb261
VZ
8062 if ( m_colWidths.IsEmpty() )
8063 {
8064 // need to really create the array
8065 InitColWidths();
8066 }
f85afd4e 8067
b99be8fb
VZ
8068 int w = wxMax( 0, width );
8069 int diff = w - m_colWidths[col];
8070 m_colWidths[col] = w;
60ff3b99 8071
7c1cb261 8072 int i;
b99be8fb 8073 for ( i = col; i < m_numCols; i++ )
f85afd4e 8074 {
b99be8fb 8075 m_colRights[i] += diff;
f85afd4e 8076 }
faec5a43
SN
8077 if ( !GetBatchCount() )
8078 CalcDimensions();
f85afd4e
MB
8079}
8080
2d66e025 8081
43947979
VZ
8082void wxGrid::SetColMinimalWidth( int col, int width )
8083{
af547d51
VZ
8084 m_colMinWidths.Put(col, width);
8085}
8086
8087void wxGrid::SetRowMinimalHeight( int row, int width )
8088{
8089 m_rowMinHeights.Put(row, width);
43947979
VZ
8090}
8091
8092int wxGrid::GetColMinimalWidth(int col) const
8093{
af547d51
VZ
8094 long value = m_colMinWidths.Get(col);
8095 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_COL_WIDTH;
8096}
8097
8098int wxGrid::GetRowMinimalHeight(int row) const
8099{
8100 long value = m_rowMinHeights.Get(row);
8101 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_ROW_HEIGHT;
43947979
VZ
8102}
8103
57c086ef
VZ
8104// ----------------------------------------------------------------------------
8105// auto sizing
8106// ----------------------------------------------------------------------------
8107
af547d51 8108void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column )
65e4e78e
VZ
8109{
8110 wxClientDC dc(m_gridWin);
8111
a95e38c0
VZ
8112 // init both of them to avoid compiler warnings, even if weo nly need one
8113 int row = -1,
8114 col = -1;
af547d51
VZ
8115 if ( column )
8116 col = colOrRow;
8117 else
8118 row = colOrRow;
8119
8120 wxCoord extent, extentMax = 0;
8121 int max = column ? m_numRows : m_numCols;
39bcce60 8122 for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
65e4e78e 8123 {
af547d51
VZ
8124 if ( column )
8125 row = rowOrCol;
8126 else
8127 col = rowOrCol;
8128
65e4e78e 8129 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 8130 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
65e4e78e
VZ
8131 if ( renderer )
8132 {
af547d51
VZ
8133 wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
8134 extent = column ? size.x : size.y;
8135 if ( extent > extentMax )
65e4e78e 8136 {
af547d51 8137 extentMax = extent;
65e4e78e 8138 }
0b190b0f
VZ
8139
8140 renderer->DecRef();
65e4e78e
VZ
8141 }
8142
8143 attr->DecRef();
8144 }
8145
af547d51
VZ
8146 // now also compare with the column label extent
8147 wxCoord w, h;
65e4e78e 8148 dc.SetFont( GetLabelFont() );
294d195c
MB
8149
8150 if ( column )
8151 dc.GetTextExtent( GetColLabelValue(col), &w, &h );
8152 else
ee495e4c 8153 dc.GetTextExtent( GetRowLabelValue(row), &w, &h );
294d195c 8154
af547d51
VZ
8155 extent = column ? w : h;
8156 if ( extent > extentMax )
65e4e78e 8157 {
af547d51 8158 extentMax = extent;
65e4e78e
VZ
8159 }
8160
af547d51 8161 if ( !extentMax )
65e4e78e 8162 {
af547d51
VZ
8163 // empty column - give default extent (notice that if extentMax is less
8164 // than default extent but != 0, it's ok)
8165 extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
65e4e78e
VZ
8166 }
8167 else
8168 {
a95e38c0
VZ
8169 if ( column )
8170 {
8171 // leave some space around text
8172 extentMax += 10;
8173 }
f6bcfd97
BP
8174 else
8175 {
8176 extentMax += 6;
8177 }
65e4e78e
VZ
8178 }
8179
faec5a43 8180 if ( column ){
af547d51 8181 SetColSize(col, extentMax);
faec5a43
SN
8182 if ( !GetBatchCount() )
8183 {
8184 int cw, ch, dummy;
8185 m_gridWin->GetClientSize( &cw, &ch );
8186 wxRect rect ( CellToRect( 0, col ) );
8187 rect.y = 0;
8188 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
8189 rect.width = cw - rect.x;
8190 rect.height = m_colLabelHeight;
8191 m_colLabelWin->Refresh( TRUE, &rect );
8192 }
8193 }
8194 else{
39bcce60 8195 SetRowSize(row, extentMax);
faec5a43
SN
8196 if ( !GetBatchCount() )
8197 {
8198 int cw, ch, dummy;
8199 m_gridWin->GetClientSize( &cw, &ch );
8200 wxRect rect ( CellToRect( row, 0 ) );
8201 rect.x = 0;
8202 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
8203 rect.width = m_rowLabelWidth;
8204 rect.height = ch - rect.y;
8205 m_rowLabelWin->Refresh( TRUE, &rect );
8206 }
8207 }
65e4e78e
VZ
8208 if ( setAsMin )
8209 {
af547d51
VZ
8210 if ( column )
8211 SetColMinimalWidth(col, extentMax);
8212 else
39bcce60 8213 SetRowMinimalHeight(row, extentMax);
65e4e78e
VZ
8214 }
8215}
8216
266e8367 8217int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
65e4e78e 8218{
57c086ef
VZ
8219 int width = m_rowLabelWidth;
8220
faec5a43
SN
8221 if ( !calcOnly )
8222 BeginBatch();
65e4e78e
VZ
8223 for ( int col = 0; col < m_numCols; col++ )
8224 {
266e8367
VZ
8225 if ( !calcOnly )
8226 {
8227 AutoSizeColumn(col, setAsMin);
8228 }
57c086ef
VZ
8229
8230 width += GetColWidth(col);
65e4e78e 8231 }
faec5a43
SN
8232 if ( !calcOnly )
8233 EndBatch();
266e8367 8234 return width;
65e4e78e
VZ
8235}
8236
266e8367 8237int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
57c086ef
VZ
8238{
8239 int height = m_colLabelHeight;
8240
faec5a43
SN
8241 if ( !calcOnly )
8242 BeginBatch();
57c086ef
VZ
8243 for ( int row = 0; row < m_numRows; row++ )
8244 {
af547d51
VZ
8245 if ( !calcOnly )
8246 {
8247 AutoSizeRow(row, setAsMin);
8248 }
57c086ef
VZ
8249
8250 height += GetRowHeight(row);
8251 }
faec5a43
SN
8252 if ( !calcOnly )
8253 EndBatch();
266e8367 8254 return height;
57c086ef
VZ
8255}
8256
8257void wxGrid::AutoSize()
8258{
266e8367 8259 // set the size too
faec5a43 8260 SetClientSize(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
266e8367
VZ
8261}
8262
8263wxSize wxGrid::DoGetBestSize() const
8264{
8265 // don't set sizes, only calculate them
8266 wxGrid *self = (wxGrid *)this; // const_cast
8267
8268 return wxSize(self->SetOrCalcColumnSizes(TRUE),
8269 self->SetOrCalcRowSizes(TRUE));
8270}
8271
8272void wxGrid::Fit()
8273{
8274 AutoSize();
57c086ef
VZ
8275}
8276
6fc0f38f
SN
8277
8278wxPen& wxGrid::GetDividerPen() const
8279{
8280 return wxNullPen;
8281}
8282
57c086ef
VZ
8283// ----------------------------------------------------------------------------
8284// cell value accessor functions
8285// ----------------------------------------------------------------------------
f85afd4e
MB
8286
8287void wxGrid::SetCellValue( int row, int col, const wxString& s )
8288{
8289 if ( m_table )
8290 {
f6bcfd97 8291 m_table->SetValue( row, col, s );
2d66e025
MB
8292 if ( !GetBatchCount() )
8293 {
8294 wxClientDC dc( m_gridWin );
8295 PrepareDC( dc );
8296 DrawCell( dc, wxGridCellCoords(row, col) );
8297 }
60ff3b99 8298
f85afd4e 8299 if ( m_currentCellCoords.GetRow() == row &&
4cfa5de6 8300 m_currentCellCoords.GetCol() == col &&
f6bcfd97
BP
8301 IsCellEditControlShown())
8302 // Note: If we are using IsCellEditControlEnabled,
8303 // this interacts badly with calling SetCellValue from
8304 // an EVT_GRID_CELL_CHANGE handler.
f85afd4e 8305 {
4cfa5de6
RD
8306 HideCellEditControl();
8307 ShowCellEditControl(); // will reread data from table
f85afd4e 8308 }
f85afd4e
MB
8309 }
8310}
8311
8312
8313//
2d66e025 8314// ------ Block, row and col selection
f85afd4e
MB
8315//
8316
8317void wxGrid::SelectRow( int row, bool addToSelected )
8318{
b5808881 8319 if ( IsSelection() && !addToSelected )
e32352cf 8320 ClearSelection();
70c7a608 8321
f6bcfd97 8322 m_selection->SelectRow( row, FALSE, addToSelected );
f85afd4e
MB
8323}
8324
8325
8326void wxGrid::SelectCol( int col, bool addToSelected )
8327{
b5808881 8328 if ( IsSelection() && !addToSelected )
e32352cf 8329 ClearSelection();
f85afd4e 8330
f6bcfd97 8331 m_selection->SelectCol( col, FALSE, addToSelected );
f85afd4e
MB
8332}
8333
8334
84912ef8 8335void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol,
c9097836 8336 bool addToSelected )
f85afd4e 8337{
c9097836
MB
8338 if ( IsSelection() && !addToSelected )
8339 ClearSelection();
f85afd4e 8340
84912ef8
RD
8341 m_selection->SelectBlock( topRow, leftCol, bottomRow, rightCol,
8342 FALSE, addToSelected );
f85afd4e
MB
8343}
8344
c9097836 8345
f85afd4e
MB
8346void wxGrid::SelectAll()
8347{
b5808881
SN
8348 m_selection->SelectBlock( 0, 0, m_numRows-1, m_numCols-1 );
8349}
f85afd4e 8350
f7b4b343
VZ
8351//
8352// ------ Cell, row and col deselection
8353//
8354
8355void wxGrid::DeselectRow( int row )
8356{
8357 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
8358 {
8359 if ( m_selection->IsInSelection(row, 0 ) )
8360 m_selection->ToggleCellSelection( row, 0);
ffdd3c98 8361 }
f7b4b343
VZ
8362 else
8363 {
8364 int nCols = GetNumberCols();
8365 for ( int i = 0; i < nCols ; i++ )
8366 {
8367 if ( m_selection->IsInSelection(row, i ) )
8368 m_selection->ToggleCellSelection( row, i);
8369 }
8370 }
8371}
8372
8373void wxGrid::DeselectCol( int col )
8374{
8375 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
8376 {
8377 if ( m_selection->IsInSelection(0, col ) )
8378 m_selection->ToggleCellSelection( 0, col);
8379 }
8380 else
8381 {
8382 int nRows = GetNumberRows();
8383 for ( int i = 0; i < nRows ; i++ )
8384 {
8385 if ( m_selection->IsInSelection(i, col ) )
8386 m_selection->ToggleCellSelection(i, col);
8387 }
8388 }
8389}
8390
8391void wxGrid::DeselectCell( int row, int col )
8392{
8393 if ( m_selection->IsInSelection(row, col) )
8394 m_selection->ToggleCellSelection(row, col);
8395}
8396
b5808881
SN
8397bool wxGrid::IsSelection()
8398{
8399 return ( m_selection->IsSelection() ||
8400 ( m_selectingTopLeft != wxGridNoCellCoords &&
8401 m_selectingBottomRight != wxGridNoCellCoords ) );
f85afd4e
MB
8402}
8403
b5808881
SN
8404bool wxGrid::IsInSelection( int row, int col )
8405{
8406 return ( m_selection->IsInSelection( row, col ) ||
8407 ( row >= m_selectingTopLeft.GetRow() &&
8408 col >= m_selectingTopLeft.GetCol() &&
8409 row <= m_selectingBottomRight.GetRow() &&
8410 col <= m_selectingBottomRight.GetCol() ) );
8411}
f85afd4e
MB
8412
8413void wxGrid::ClearSelection()
8414{
b5808881
SN
8415 m_selectingTopLeft = wxGridNoCellCoords;
8416 m_selectingBottomRight = wxGridNoCellCoords;
8417 m_selection->ClearSelection();
8f177c8e 8418}
f85afd4e
MB
8419
8420
da6af900 8421// This function returns the rectangle that encloses the given block
2d66e025
MB
8422// in device coords clipped to the client size of the grid window.
8423//
58dd5b3b
MB
8424wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
8425 const wxGridCellCoords &bottomRight )
f85afd4e 8426{
58dd5b3b 8427 wxRect rect( wxGridNoCellRect );
f85afd4e
MB
8428 wxRect cellRect;
8429
58dd5b3b
MB
8430 cellRect = CellToRect( topLeft );
8431 if ( cellRect != wxGridNoCellRect )
f85afd4e 8432 {
58dd5b3b
MB
8433 rect = cellRect;
8434 }
8435 else
8436 {
8437 rect = wxRect( 0, 0, 0, 0 );
8438 }
60ff3b99 8439
58dd5b3b
MB
8440 cellRect = CellToRect( bottomRight );
8441 if ( cellRect != wxGridNoCellRect )
8442 {
8443 rect += cellRect;
2d66e025
MB
8444 }
8445 else
8446 {
8447 return wxGridNoCellRect;
f85afd4e
MB
8448 }
8449
58dd5b3b
MB
8450 // convert to scrolled coords
8451 //
8452 int left, top, right, bottom;
8453 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
8454 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
8455
8456 int cw, ch;
8457 m_gridWin->GetClientSize( &cw, &ch );
8458
f6bcfd97
BP
8459 if (right < 0 || bottom < 0 || left > cw || top > ch)
8460 return wxRect( 0, 0, 0, 0);
8461
58dd5b3b
MB
8462 rect.SetLeft( wxMax(0, left) );
8463 rect.SetTop( wxMax(0, top) );
8464 rect.SetRight( wxMin(cw, right) );
8465 rect.SetBottom( wxMin(ch, bottom) );
8466
f85afd4e
MB
8467 return rect;
8468}
8469
8470
58dd5b3b 8471
f85afd4e
MB
8472//
8473// ------ Grid event classes
8474//
8475
8476IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
8477
8478wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
5c8fc7c1 8479 int row, int col, int x, int y, bool sel,
f85afd4e
MB
8480 bool control, bool shift, bool alt, bool meta )
8481 : wxNotifyEvent( type, id )
8482{
8483 m_row = row;
8484 m_col = col;
8485 m_x = x;
8486 m_y = y;
5c8fc7c1 8487 m_selecting = sel;
f85afd4e
MB
8488 m_control = control;
8489 m_shift = shift;
8490 m_alt = alt;
8491 m_meta = meta;
8f177c8e 8492
f85afd4e
MB
8493 SetEventObject(obj);
8494}
8495
8496
8497IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
8498
8499wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
8500 int rowOrCol, int x, int y,
8501 bool control, bool shift, bool alt, bool meta )
8502 : wxNotifyEvent( type, id )
8503{
8504 m_rowOrCol = rowOrCol;
8505 m_x = x;
8506 m_y = y;
8507 m_control = control;
8508 m_shift = shift;
8509 m_alt = alt;
8510 m_meta = meta;
8f177c8e 8511
f85afd4e
MB
8512 SetEventObject(obj);
8513}
8514
8515
8516IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
8517
8518wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
8f177c8e
VZ
8519 const wxGridCellCoords& topLeft,
8520 const wxGridCellCoords& bottomRight,
5c8fc7c1
SN
8521 bool sel, bool control,
8522 bool shift, bool alt, bool meta )
8f177c8e 8523 : wxNotifyEvent( type, id )
f85afd4e
MB
8524{
8525 m_topLeft = topLeft;
8526 m_bottomRight = bottomRight;
5c8fc7c1 8527 m_selecting = sel;
f85afd4e
MB
8528 m_control = control;
8529 m_shift = shift;
8530 m_alt = alt;
8531 m_meta = meta;
8532
8533 SetEventObject(obj);
8534}
8535
8536
8537#endif // ifndef wxUSE_NEW_GRID