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