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