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