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