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