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