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