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