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