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