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