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