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