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