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