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