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