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