]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/grid.cpp
Additional imageId values for specific drive types on OS/2.
[wxWidgets.git] / src / generic / grid.cpp
... / ...
Content-type: text/html ]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/grid.cpp


500 - Internal Server Error

Malformed UTF-8 character (fatal) at /usr/lib/x86_64-linux-gnu/perl5/5.40/HTML/Entities.pm line 485, <$fd> line 3912.
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: Robin Dunn, Vadim Zeitlin
6// Created: 1/08/1999
7// RCS-ID: $Id$
8// Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "grid.h"
22#endif
23
24// For compilers that support precompilatixon, includes "wx/wx.h".
25#include "wx/wxprec.h"
26
27#include "wx/defs.h"
28
29#ifdef __BORLANDC__
30 #pragma hdrstop
31#endif
32
33#if wxUSE_GRID
34
35#ifndef WX_PRECOMP
36 #include "wx/utils.h"
37 #include "wx/dcclient.h"
38 #include "wx/settings.h"
39 #include "wx/log.h"
40 #include "wx/textctrl.h"
41 #include "wx/checkbox.h"
42 #include "wx/combobox.h"
43 #include "wx/valtext.h"
44 #include "wx/intl.h"
45#endif
46
47#include "wx/textfile.h"
48#include "wx/spinctrl.h"
49#include "wx/tokenzr.h"
50#include "wx/renderer.h"
51
52#include "wx/grid.h"
53#include "wx/generic/gridsel.h"
54
55#if defined(__WXMOTIF__)
56 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
57#else
58 #define WXUNUSED_MOTIF(identifier) identifier
59#endif
60
61#if defined(__WXGTK__)
62 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
63#else
64 #define WXUNUSED_GTK(identifier) identifier
65#endif
66
67// Required for wxIs... functions
68#include <ctype.h>
69
70// ----------------------------------------------------------------------------
71// array classes
72// ----------------------------------------------------------------------------
73
74WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridCellAttr *, wxArrayAttrs,
75 class WXDLLIMPEXP_ADV);
76
77struct wxGridCellWithAttr
78{
79 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
80 : coords(row, col), attr(attr_)
81 {
82 }
83
84 ~wxGridCellWithAttr()
85 {
86 attr->DecRef();
87 }
88
89 wxGridCellCoords coords;
90 wxGridCellAttr *attr;
91
92// Cannot do this:
93// DECLARE_NO_COPY_CLASS(wxGridCellWithAttr)
94// without rewriting the macros, which require a public copy constructor.
95};
96
97WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellWithAttr, wxGridCellWithAttrArray,
98 class WXDLLIMPEXP_ADV);
99
100#include "wx/arrimpl.cpp"
101
102WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
103WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
104
105// ----------------------------------------------------------------------------
106// events
107// ----------------------------------------------------------------------------
108
109DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK)
110DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK)
111DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK)
112DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK)
113DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_BEGIN_DRAG)
114DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK)
115DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK)
116DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK)
117DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK)
118DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE)
119DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE)
120DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT)
121DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE)
122DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL)
123DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN)
124DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN)
125DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED)
126
127// ----------------------------------------------------------------------------
128// private classes
129// ----------------------------------------------------------------------------
130
131class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxWindow
132{
133public:
134 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
135 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
136 const wxPoint &pos, const wxSize &size );
137
138private:
139 wxGrid *m_owner;
140
141 void OnPaint( wxPaintEvent& event );
142 void OnMouseEvent( wxMouseEvent& event );
143 void OnMouseWheel( wxMouseEvent& event );
144 void OnKeyDown( wxKeyEvent& event );
145 void OnKeyUp( wxKeyEvent& );
146 void OnChar( wxKeyEvent& );
147
148 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
149 DECLARE_EVENT_TABLE()
150 DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow)
151};
152
153
154class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxWindow
155{
156public:
157 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
158 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
159 const wxPoint &pos, const wxSize &size );
160
161private:
162 wxGrid *m_owner;
163
164 void OnPaint( wxPaintEvent &event );
165 void OnMouseEvent( wxMouseEvent& event );
166 void OnMouseWheel( wxMouseEvent& event );
167 void OnKeyDown( wxKeyEvent& event );
168 void OnKeyUp( wxKeyEvent& );
169 void OnChar( wxKeyEvent& );
170
171 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
172 DECLARE_EVENT_TABLE()
173 DECLARE_NO_COPY_CLASS(wxGridColLabelWindow)
174};
175
176
177class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxWindow
178{
179public:
180 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
181 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
182 const wxPoint &pos, const wxSize &size );
183
184private:
185 wxGrid *m_owner;
186
187 void OnMouseEvent( wxMouseEvent& event );
188 void OnMouseWheel( wxMouseEvent& event );
189 void OnKeyDown( wxKeyEvent& event );
190 void OnKeyUp( wxKeyEvent& );
191 void OnChar( wxKeyEvent& );
192 void OnPaint( wxPaintEvent& event );
193
194 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
195 DECLARE_EVENT_TABLE()
196 DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow)
197};
198
199class WXDLLIMPEXP_ADV wxGridWindow : public wxWindow
200{
201public:
202 wxGridWindow()
203 {
204 m_owner = (wxGrid *)NULL;
205 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
206 m_colLabelWin = (wxGridColLabelWindow *)NULL;
207 }
208
209 wxGridWindow( wxGrid *parent,
210 wxGridRowLabelWindow *rowLblWin,
211 wxGridColLabelWindow *colLblWin,
212 wxWindowID id, const wxPoint &pos, const wxSize &size );
213 ~wxGridWindow(){}
214
215 void ScrollWindow( int dx, int dy, const wxRect *rect );
216
217 wxGrid* GetOwner() { return m_owner; }
218
219private:
220 wxGrid *m_owner;
221 wxGridRowLabelWindow *m_rowLabelWin;
222 wxGridColLabelWindow *m_colLabelWin;
223
224 void OnPaint( wxPaintEvent &event );
225 void OnMouseWheel( wxMouseEvent& event );
226 void OnMouseEvent( wxMouseEvent& event );
227 void OnKeyDown( wxKeyEvent& );
228 void OnKeyUp( wxKeyEvent& );
229 void OnChar( wxKeyEvent& );
230 void OnEraseBackground( wxEraseEvent& );
231 void OnFocus( wxFocusEvent& );
232
233 DECLARE_DYNAMIC_CLASS(wxGridWindow)
234 DECLARE_EVENT_TABLE()
235 DECLARE_NO_COPY_CLASS(wxGridWindow)
236};
237
238
239
240class wxGridCellEditorEvtHandler : public wxEvtHandler
241{
242public:
243 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
244 : m_grid(grid),
245 m_editor(editor),
246 m_inSetFocus(false)
247 {
248 }
249
250 void OnKillFocus(wxFocusEvent& event);
251 void OnKeyDown(wxKeyEvent& event);
252 void OnChar(wxKeyEvent& event);
253
254 void SetInSetFocus(bool inSetFocus) { m_inSetFocus = inSetFocus; }
255
256private:
257 wxGrid* m_grid;
258 wxGridCellEditor* m_editor;
259
260 // Work around the fact that a focus kill event can be sent to
261 // a combobox within a set focus event.
262 bool m_inSetFocus;
263
264 DECLARE_EVENT_TABLE()
265 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
266 DECLARE_NO_COPY_CLASS(wxGridCellEditorEvtHandler)
267};
268
269
270IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler, wxEvtHandler)
271
272BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
273 EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus )
274 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
275 EVT_CHAR( wxGridCellEditorEvtHandler::OnChar )
276END_EVENT_TABLE()
277
278
279
280// ----------------------------------------------------------------------------
281// the internal data representation used by wxGridCellAttrProvider
282// ----------------------------------------------------------------------------
283
284// this class stores attributes set for cells
285class WXDLLIMPEXP_ADV wxGridCellAttrData
286{
287public:
288 void SetAttr(wxGridCellAttr *attr, int row, int col);
289 wxGridCellAttr *GetAttr(int row, int col) const;
290 void UpdateAttrRows( size_t pos, int numRows );
291 void UpdateAttrCols( size_t pos, int numCols );
292
293private:
294 // searches for the attr for given cell, returns wxNOT_FOUND if not found
295 int FindIndex(int row, int col) const;
296
297 wxGridCellWithAttrArray m_attrs;
298};
299
300// this class stores attributes set for rows or columns
301class WXDLLIMPEXP_ADV wxGridRowOrColAttrData
302{
303public:
304 // empty ctor to suppress warnings
305 wxGridRowOrColAttrData() { }
306 ~wxGridRowOrColAttrData();
307
308 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
309 wxGridCellAttr *GetAttr(int rowOrCol) const;
310 void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols );
311
312private:
313 wxArrayInt m_rowsOrCols;
314 wxArrayAttrs m_attrs;
315};
316
317// NB: this is just a wrapper around 3 objects: one which stores cell
318// attributes, and 2 others for row/col ones
319class WXDLLIMPEXP_ADV wxGridCellAttrProviderData
320{
321public:
322 wxGridCellAttrData m_cellAttrs;
323 wxGridRowOrColAttrData m_rowAttrs,
324 m_colAttrs;
325};
326
327
328// ----------------------------------------------------------------------------
329// data structures used for the data type registry
330// ----------------------------------------------------------------------------
331
332struct wxGridDataTypeInfo
333{
334 wxGridDataTypeInfo(const wxString& typeName,
335 wxGridCellRenderer* renderer,
336 wxGridCellEditor* editor)
337 : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
338 { }
339
340 ~wxGridDataTypeInfo()
341 {
342 wxSafeDecRef(m_renderer);
343 wxSafeDecRef(m_editor);
344 }
345
346 wxString m_typeName;
347 wxGridCellRenderer* m_renderer;
348 wxGridCellEditor* m_editor;
349
350 DECLARE_NO_COPY_CLASS(wxGridDataTypeInfo)
351};
352
353
354WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridDataTypeInfo*, wxGridDataTypeInfoArray,
355 class WXDLLIMPEXP_ADV);
356
357
358class WXDLLIMPEXP_ADV wxGridTypeRegistry
359{
360public:
361 wxGridTypeRegistry() {}
362 ~wxGridTypeRegistry();
363
364 void RegisterDataType(const wxString& typeName,
365 wxGridCellRenderer* renderer,
366 wxGridCellEditor* editor);
367
368 // find one of already registered data types
369 int FindRegisteredDataType(const wxString& typeName);
370
371 // try to FindRegisteredDataType(), if this fails and typeName is one of
372 // standard typenames, register it and return its index
373 int FindDataType(const wxString& typeName);
374
375 // try to FindDataType(), if it fails see if it is not one of already
376 // registered data types with some params in which case clone the
377 // registered data type and set params for it
378 int FindOrCloneDataType(const wxString& typeName);
379
380 wxGridCellRenderer* GetRenderer(int index);
381 wxGridCellEditor* GetEditor(int index);
382
383private:
384 wxGridDataTypeInfoArray m_typeinfo;
385};
386
387// ----------------------------------------------------------------------------
388// conditional compilation
389// ----------------------------------------------------------------------------
390
391#ifndef WXGRID_DRAW_LINES
392#define WXGRID_DRAW_LINES 1
393#endif
394
395// ----------------------------------------------------------------------------
396// globals
397// ----------------------------------------------------------------------------
398
399//#define DEBUG_ATTR_CACHE
400#ifdef DEBUG_ATTR_CACHE
401 static size_t gs_nAttrCacheHits = 0;
402 static size_t gs_nAttrCacheMisses = 0;
403#endif // DEBUG_ATTR_CACHE
404
405// ----------------------------------------------------------------------------
406// constants
407// ----------------------------------------------------------------------------
408
409wxGridCellCoords wxGridNoCellCoords( -1, -1 );
410wxRect wxGridNoCellRect( -1, -1, -1, -1 );
411
412// scroll line size
413// TODO: this doesn't work at all, grid cells have different sizes and approx
414// calculations don't work as because of the size mismatch scrollbars
415// sometimes fail to be shown when they should be or vice versa
416//
417// The scroll bars may be a little flakey once in a while, but that is
418// surely much less horrible than having scroll lines of only 1!!!
419// -- Robin
420//
421// Well, it's still seriously broken so it might be better but needs
422// fixing anyhow
423// -- Vadim
424static const size_t GRID_SCROLL_LINE_X = 15; // 1;
425static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
426
427// the size of hash tables used a bit everywhere (the max number of elements
428// in these hash tables is the number of rows/columns)
429static const int GRID_HASH_SIZE = 100;
430
431#if 0
432// ----------------------------------------------------------------------------
433// private functions
434// ----------------------------------------------------------------------------
435
436static inline int GetScrollX(int x)
437{
438 return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X;
439}
440
441static inline int GetScrollY(int y)
442{
443 return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y;
444}
445#endif
446
447// ============================================================================
448// implementation
449// ============================================================================
450
451// ----------------------------------------------------------------------------
452// wxGridCellEditor
453// ----------------------------------------------------------------------------
454
455wxGridCellEditor::wxGridCellEditor()
456{
457 m_control = NULL;
458 m_attr = NULL;
459}
460
461
462wxGridCellEditor::~wxGridCellEditor()
463{
464 Destroy();
465}
466
467void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
468 wxWindowID WXUNUSED(id),
469 wxEvtHandler* evtHandler)
470{
471 if ( evtHandler )
472 m_control->PushEventHandler(evtHandler);
473}
474
475void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
476 wxGridCellAttr *attr)
477{
478 // erase the background because we might not fill the cell
479 wxClientDC dc(m_control->GetParent());
480 wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
481 if (gridWindow)
482 gridWindow->GetOwner()->PrepareDC(dc);
483
484 dc.SetPen(*wxTRANSPARENT_PEN);
485 dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
486 dc.DrawRectangle(rectCell);
487
488 // redraw the control we just painted over
489 m_control->Refresh();
490}
491
492void wxGridCellEditor::Destroy()
493{
494 if (m_control)
495 {
496 m_control->PopEventHandler(true /* delete it*/);
497
498 m_control->Destroy();
499 m_control = NULL;
500 }
501}
502
503void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
504{
505 wxASSERT_MSG(m_control,
506 wxT("The wxGridCellEditor must be Created first!"));
507 m_control->Show(show);
508
509 if ( show )
510 {
511 // set the colours/fonts if we have any
512 if ( attr )
513 {
514 m_colFgOld = m_control->GetForegroundColour();
515 m_control->SetForegroundColour(attr->GetTextColour());
516
517 m_colBgOld = m_control->GetBackgroundColour();
518 m_control->SetBackgroundColour(attr->GetBackgroundColour());
519
520// Workaround for GTK+1 font setting problem on some platforms
521#if !defined(__WXGTK__) || defined(__WXGTK20__)
522 m_fontOld = m_control->GetFont();
523 m_control->SetFont(attr->GetFont());
524#endif
525 // can't do anything more in the base class version, the other
526 // attributes may only be used by the derived classes
527 }
528 }
529 else
530 {
531 // restore the standard colours fonts
532 if ( m_colFgOld.Ok() )
533 {
534 m_control->SetForegroundColour(m_colFgOld);
535 m_colFgOld = wxNullColour;
536 }
537
538 if ( m_colBgOld.Ok() )
539 {
540 m_control->SetBackgroundColour(m_colBgOld);
541 m_colBgOld = wxNullColour;
542 }
543// Workaround for GTK+1 font setting problem on some platforms
544#if !defined(__WXGTK__) || defined(__WXGTK20__)
545 if ( m_fontOld.Ok() )
546 {
547 m_control->SetFont(m_fontOld);
548 m_fontOld = wxNullFont;
549 }
550#endif
551 }
552}
553
554void wxGridCellEditor::SetSize(const wxRect& rect)
555{
556 wxASSERT_MSG(m_control,
557 wxT("The wxGridCellEditor must be Created first!"));
558 m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
559}
560
561void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
562{
563 event.Skip();
564}
565
566bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
567{
568 bool ctrl = event.ControlDown();
569 bool alt = event.AltDown();
570#ifdef __WXMAC__
571 // On the Mac the Alt key is more like shift and is used for entry of
572 // valid characters, so check for Ctrl and Meta instead.
573 alt = event.MetaDown();
574#endif
575
576 // Assume it's not a valid char if ctrl or alt is down, but if both are
577 // down then it may be because of an AltGr key combination, so let them
578 // through in that case.
579 if ((ctrl || alt) && !(ctrl && alt))
580 return false;
581
582#if wxUSE_UNICODE
583 int key = event.GetUnicodeKey();
584 bool keyOk = true;
585
586 // if the unicode key code is not really a unicode character (it may
587 // be a function key or etc., the platforms appear to always give us a
588 // small value in this case) then fallback to the ascii key code but
589 // don't do anything for function keys or etc.
590 if (key <= 127)
591 {
592 key = event.GetKeyCode();
593 keyOk = (key <= 127);
594 }
595 return keyOk;
596#else // !wxUSE_UNICODE
597 int key = event.GetKeyCode();
598 if (key <= 255)
599 return true;
600 return false;
601#endif // wxUSE_UNICODE/!wxUSE_UNICODE
602}
603
604void wxGridCellEditor::StartingKey(wxKeyEvent& event)
605{
606 event.Skip();
607}
608
609void wxGridCellEditor::StartingClick()
610{
611}
612
613#if wxUSE_TEXTCTRL
614
615// ----------------------------------------------------------------------------
616// wxGridCellTextEditor
617// ----------------------------------------------------------------------------
618
619wxGridCellTextEditor::wxGridCellTextEditor()
620{
621 m_maxChars = 0;
622}
623
624void wxGridCellTextEditor::Create(wxWindow* parent,
625 wxWindowID id,
626 wxEvtHandler* evtHandler)
627{
628 m_control = new wxTextCtrl(parent, id, wxEmptyString,
629 wxDefaultPosition, wxDefaultSize
630#if defined(__WXMSW__)
631 , wxTE_PROCESS_TAB | wxTE_AUTO_SCROLL
632#endif
633 );
634
635 // set max length allowed in the textctrl, if the parameter was set
636 if (m_maxChars != 0)
637 {
638 ((wxTextCtrl*)m_control)->SetMaxLength(m_maxChars);
639 }
640
641 wxGridCellEditor::Create(parent, id, evtHandler);
642}
643
644void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
645 wxGridCellAttr * WXUNUSED(attr))
646{
647 // as we fill the entire client area, don't do anything here to minimize
648 // flicker
649}
650
651void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
652{
653 wxRect rect(rectOrig);
654
655 // Make the edit control large enough to allow for internal
656 // margins
657 //
658 // TODO: remove this if the text ctrl sizing is improved esp. for
659 // unix
660 //
661#if defined(__WXGTK__)
662 if (rect.x != 0)
663 {
664 rect.x += 1;
665 rect.y += 1;
666 rect.width -= 1;
667 rect.height -= 1;
668 }
669#else // !GTK
670 int extra_x = ( rect.x > 2 )? 2 : 1;
671
672// MB: treat MSW separately here otherwise the caret doesn't show
673// when the editor is in the first row.
674#if defined(__WXMSW__)
675 int extra_y = 2;
676#else
677 int extra_y = ( rect.y > 2 )? 2 : 1;
678#endif // MSW
679
680#if defined(__WXMOTIF__)
681 extra_x *= 2;
682 extra_y *= 2;
683#endif
684 rect.SetLeft( wxMax(0, rect.x - extra_x) );
685 rect.SetTop( wxMax(0, rect.y - extra_y) );
686 rect.SetRight( rect.GetRight() + 2*extra_x );
687 rect.SetBottom( rect.GetBottom() + 2*extra_y );
688#endif // GTK/!GTK
689
690 wxGridCellEditor::SetSize(rect);
691}
692
693void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
694{
695 wxASSERT_MSG(m_control,
696 wxT("The wxGridCellEditor must be Created first!"));
697
698 m_startValue = grid->GetTable()->GetValue(row, col);
699
700 DoBeginEdit(m_startValue);
701}
702
703void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
704{
705 Text()->SetValue(startValue);
706 Text()->SetInsertionPointEnd();
707 Text()->SetSelection(-1,-1);
708 Text()->SetFocus();
709}
710
711bool wxGridCellTextEditor::EndEdit(int row, int col,
712 wxGrid* grid)
713{
714 wxASSERT_MSG(m_control,
715 wxT("The wxGridCellEditor must be Created first!"));
716
717 bool changed = false;
718 wxString value = Text()->GetValue();
719 if (value != m_startValue)
720 changed = true;
721
722 if (changed)
723 grid->GetTable()->SetValue(row, col, value);
724
725 m_startValue = wxEmptyString;
726 // No point in setting the text of the hidden control
727 //Text()->SetValue(m_startValue);
728
729 return changed;
730}
731
732
733void wxGridCellTextEditor::Reset()
734{
735 wxASSERT_MSG(m_control,
736 wxT("The wxGridCellEditor must be Created first!"));
737
738 DoReset(m_startValue);
739}
740
741void wxGridCellTextEditor::DoReset(const wxString& startValue)
742{
743 Text()->SetValue(startValue);
744 Text()->SetInsertionPointEnd();
745}
746
747bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
748{
749 return wxGridCellEditor::IsAcceptedKey(event);
750}
751
752void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
753{
754 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
755 // longer an appropriate way to get the character into the text control.
756 // Do it ourselves instead. We know that if we get this far that we have
757 // a valid character, so not a whole lot of testing needs to be done.
758
759 wxTextCtrl* tc = Text();
760 wxChar ch;
761 long pos;
762
763#if wxUSE_UNICODE
764 ch = event.GetUnicodeKey();
765 if (ch <= 127)
766 ch = (wxChar)event.GetKeyCode();
767#else
768 ch = (wxChar)event.GetKeyCode();
769#endif
770 switch (ch)
771 {
772 case WXK_DELETE:
773 // delete the character at the cursor
774 pos = tc->GetInsertionPoint();
775 if (pos < tc->GetLastPosition())
776 tc->Remove(pos, pos+1);
777 break;
778
779 case WXK_BACK:
780 // delete the character before the cursor
781 pos = tc->GetInsertionPoint();
782 if (pos > 0)
783 tc->Remove(pos-1, pos);
784 break;
785
786 default:
787 tc->WriteText(ch);
788 break;
789 }
790}
791
792void wxGridCellTextEditor::HandleReturn( wxKeyEvent&
793 WXUNUSED_GTK(WXUNUSED_MOTIF(event)) )
794{
795#if defined(__WXMOTIF__) || defined(__WXGTK__)
796 // wxMotif needs a little extra help...
797 size_t pos = (size_t)( Text()->GetInsertionPoint() );
798 wxString s( Text()->GetValue() );
799 s = s.Left(pos) + wxT("\n") + s.Mid(pos);
800 Text()->SetValue(s);
801 Text()->SetInsertionPoint( pos );
802#else
803 // the other ports can handle a Return key press
804 //
805 event.Skip();
806#endif
807}
808
809void wxGridCellTextEditor::SetParameters(const wxString& params)
810{
811 if ( !params )
812 {
813 // reset to default
814 m_maxChars = 0;
815 }
816 else
817 {
818 long tmp;
819 if ( !params.ToLong(&tmp) )
820 {
821 wxLogDebug(_T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str());
822 }
823 else
824 {
825 m_maxChars = (size_t)tmp;
826 }
827 }
828}
829
830// return the value in the text control
831wxString wxGridCellTextEditor::GetValue() const
832{
833 return Text()->GetValue();
834}
835
836// ----------------------------------------------------------------------------
837// wxGridCellNumberEditor
838// ----------------------------------------------------------------------------
839
840wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
841{
842 m_min = min;
843 m_max = max;
844}
845
846void wxGridCellNumberEditor::Create(wxWindow* parent,
847 wxWindowID id,
848 wxEvtHandler* evtHandler)
849{
850#if wxUSE_SPINCTRL
851 if ( HasRange() )
852 {
853 // create a spin ctrl
854 m_control = new wxSpinCtrl(parent, wxID_ANY, wxEmptyString,
855 wxDefaultPosition, wxDefaultSize,
856 wxSP_ARROW_KEYS,
857 m_min, m_max);
858
859 wxGridCellEditor::Create(parent, id, evtHandler);
860 }
861 else
862#endif
863 {
864 // just a text control
865 wxGridCellTextEditor::Create(parent, id, evtHandler);
866
867#if wxUSE_VALIDATORS
868 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
869#endif // wxUSE_VALIDATORS
870 }
871}
872
873void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
874{
875 // first get the value
876 wxGridTableBase *table = grid->GetTable();
877 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
878 {
879 m_valueOld = table->GetValueAsLong(row, col);
880 }
881 else
882 {
883 m_valueOld = 0;
884 wxString sValue = table->GetValue(row, col);
885 if (! sValue.ToLong(&m_valueOld) && ! sValue.empty())
886 {
887 wxFAIL_MSG( _T("this cell doesn't have numeric value") );
888 return;
889 }
890 }
891
892#if wxUSE_SPINCTRL
893 if ( HasRange() )
894 {
895 Spin()->SetValue((int)m_valueOld);
896 Spin()->SetFocus();
897 }
898 else
899#endif
900 {
901 DoBeginEdit(GetString());
902 }
903}
904
905bool wxGridCellNumberEditor::EndEdit(int row, int col,
906 wxGrid* grid)
907{
908 bool changed;
909 long value = 0;
910 wxString text;
911
912#if wxUSE_SPINCTRL
913 if ( HasRange() )
914 {
915 value = Spin()->GetValue();
916 changed = value != m_valueOld;
917 if (changed)
918 text = wxString::Format(wxT("%ld"), value);
919 }
920 else
921#endif
922 {
923 text = Text()->GetValue();
924 changed = (text.empty() || text.ToLong(&value)) && (value != m_valueOld);
925 }
926
927 if ( changed )
928 {
929 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
930 grid->GetTable()->SetValueAsLong(row, col, value);
931 else
932 grid->GetTable()->SetValue(row, col, text);
933 }
934
935 return changed;
936}
937
938void wxGridCellNumberEditor::Reset()
939{
940#if wxUSE_SPINCTRL
941 if ( HasRange() )
942 {
943 Spin()->SetValue((int)m_valueOld);
944 }
945 else
946#endif
947 {
948 DoReset(GetString());
949 }
950}
951
952bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event)
953{
954 if ( wxGridCellEditor::IsAcceptedKey(event) )
955 {
956 int keycode = event.GetKeyCode();
957 if ( (keycode < 128) &&
958 (wxIsdigit(keycode) || keycode == '+' || keycode == '-'))
959 {
960 return true;
961 }
962 }
963
964 return false;
965}
966
967void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
968{
969 int keycode = event.GetKeyCode();
970 if ( !HasRange() )
971 {
972 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-')
973 {
974 wxGridCellTextEditor::StartingKey(event);
975
976 // skip Skip() below
977 return;
978 }
979 }
980#if wxUSE_SPINCTRL
981 else
982 {
983 if ( wxIsdigit(keycode) )
984 {
985 wxSpinCtrl* spin = (wxSpinCtrl*)m_control;
986 spin->SetValue(keycode - '0');
987 spin->SetSelection(1,1);
988 return;
989 }
990 }
991#endif
992 event.Skip();
993}
994
995void wxGridCellNumberEditor::SetParameters(const wxString& params)
996{
997 if ( !params )
998 {
999 // reset to default
1000 m_min =
1001 m_max = -1;
1002 }
1003 else
1004 {
1005 long tmp;
1006 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1007 {
1008 m_min = (int)tmp;
1009
1010 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1011 {
1012 m_max = (int)tmp;
1013
1014 // skip the error message below
1015 return;
1016 }
1017 }
1018
1019 wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
1020 }
1021}
1022
1023// return the value in the spin control if it is there (the text control otherwise)
1024wxString wxGridCellNumberEditor::GetValue() const
1025{
1026 wxString s;
1027
1028#if wxUSE_SPINCTRL
1029 if( HasRange() )
1030 {
1031 long value = Spin()->GetValue();
1032 s.Printf(wxT("%ld"), value);
1033 }
1034 else
1035#endif
1036 {
1037 s = Text()->GetValue();
1038 }
1039
1040 return s;
1041}
1042
1043// ----------------------------------------------------------------------------
1044// wxGridCellFloatEditor
1045// ----------------------------------------------------------------------------
1046
1047wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision)
1048{
1049 m_width = width;
1050 m_precision = precision;
1051}
1052
1053void wxGridCellFloatEditor::Create(wxWindow* parent,
1054 wxWindowID id,
1055 wxEvtHandler* evtHandler)
1056{
1057 wxGridCellTextEditor::Create(parent, id, evtHandler);
1058
1059#if wxUSE_VALIDATORS
1060 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
1061#endif // wxUSE_VALIDATORS
1062}
1063
1064void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
1065{
1066 // first get the value
1067 wxGridTableBase *table = grid->GetTable();
1068 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1069 {
1070 m_valueOld = table->GetValueAsDouble(row, col);
1071 }
1072 else
1073 {
1074 m_valueOld = 0.0;
1075 wxString sValue = table->GetValue(row, col);
1076 if (! sValue.ToDouble(&m_valueOld) && ! sValue.empty())
1077 {
1078 wxFAIL_MSG( _T("this cell doesn't have float value") );
1079 return;
1080 }
1081 }
1082
1083 DoBeginEdit(GetString());
1084}
1085
1086bool wxGridCellFloatEditor::EndEdit(int row, int col,
1087 wxGrid* grid)
1088{
1089 double value = 0.0;
1090 wxString text(Text()->GetValue());
1091
1092 if ( (text.empty() || text.ToDouble(&value)) && (value != m_valueOld) )
1093 {
1094 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
1095 grid->GetTable()->SetValueAsDouble(row, col, value);
1096 else
1097 grid->GetTable()->SetValue(row, col, text);
1098
1099 return true;
1100 }
1101 return false;
1102}
1103
1104void wxGridCellFloatEditor::Reset()
1105{
1106 DoReset(GetString());
1107}
1108
1109void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
1110{
1111 int keycode = event.GetKeyCode();
1112 char tmpbuf[2];
1113 tmpbuf[0] = (char) keycode;
1114 tmpbuf[1] = '\0';
1115 wxString strbuf(tmpbuf, *wxConvCurrent);
1116#if wxUSE_INTL
1117 bool is_decimal_point = ( strbuf ==
1118 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) );
1119#else
1120 bool is_decimal_point = ( strbuf == _T(".") );
1121#endif
1122 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-'
1123 || is_decimal_point )
1124 {
1125 wxGridCellTextEditor::StartingKey(event);
1126
1127 // skip Skip() below
1128 return;
1129 }
1130
1131 event.Skip();
1132}
1133
1134void wxGridCellFloatEditor::SetParameters(const wxString& params)
1135{
1136 if ( !params )
1137 {
1138 // reset to default
1139 m_width =
1140 m_precision = -1;
1141 }
1142 else
1143 {
1144 long tmp;
1145 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1146 {
1147 m_width = (int)tmp;
1148
1149 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1150 {
1151 m_precision = (int)tmp;
1152
1153 // skip the error message below
1154 return;
1155 }
1156 }
1157
1158 wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str());
1159 }
1160}
1161
1162wxString wxGridCellFloatEditor::GetString() const
1163{
1164 wxString fmt;
1165 if ( m_width == -1 )
1166 {
1167 // default width/precision
1168 fmt = _T("%f");
1169 }
1170 else if ( m_precision == -1 )
1171 {
1172 // default precision
1173 fmt.Printf(_T("%%%d.f"), m_width);
1174 }
1175 else
1176 {
1177 fmt.Printf(_T("%%%d.%df"), m_width, m_precision);
1178 }
1179
1180 return wxString::Format(fmt, m_valueOld);
1181}
1182
1183bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
1184{
1185 if ( wxGridCellEditor::IsAcceptedKey(event) )
1186 {
1187 int keycode = event.GetKeyCode();
1188 printf("%d\n", keycode);
1189 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1190 char tmpbuf[2];
1191 tmpbuf[0] = (char) keycode;
1192 tmpbuf[1] = '\0';
1193 wxString strbuf(tmpbuf, *wxConvCurrent);
1194#if wxUSE_INTL
1195 bool is_decimal_point =
1196 ( strbuf == wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT,
1197 wxLOCALE_CAT_NUMBER) );
1198#else
1199 bool is_decimal_point = ( strbuf == _T(".") );
1200#endif
1201 if ( (keycode < 128) &&
1202 (wxIsdigit(keycode) || tolower(keycode) == 'e' ||
1203 is_decimal_point || keycode == '+' || keycode == '-') )
1204 return true;
1205 }
1206
1207 return false;
1208}
1209
1210#endif // wxUSE_TEXTCTRL
1211
1212#if wxUSE_CHECKBOX
1213
1214// ----------------------------------------------------------------------------
1215// wxGridCellBoolEditor
1216// ----------------------------------------------------------------------------
1217
1218void wxGridCellBoolEditor::Create(wxWindow* parent,
1219 wxWindowID id,
1220 wxEvtHandler* evtHandler)
1221{
1222 m_control = new wxCheckBox(parent, id, wxEmptyString,
1223 wxDefaultPosition, wxDefaultSize,
1224 wxNO_BORDER);
1225
1226 wxGridCellEditor::Create(parent, id, evtHandler);
1227}
1228
1229void wxGridCellBoolEditor::SetSize(const wxRect& r)
1230{
1231 bool resize = false;
1232 wxSize size = m_control->GetSize();
1233 wxCoord minSize = wxMin(r.width, r.height);
1234
1235 // check if the checkbox is not too big/small for this cell
1236 wxSize sizeBest = m_control->GetBestSize();
1237 if ( !(size == sizeBest) )
1238 {
1239 // reset to default size if it had been made smaller
1240 size = sizeBest;
1241
1242 resize = true;
1243 }
1244
1245 if ( size.x >= minSize || size.y >= minSize )
1246 {
1247 // leave 1 pixel margin
1248 size.x = size.y = minSize - 2;
1249
1250 resize = true;
1251 }
1252
1253 if ( resize )
1254 {
1255 m_control->SetSize(size);
1256 }
1257
1258 // position it in the centre of the rectangle (TODO: support alignment?)
1259
1260#if defined(__WXGTK__) || defined (__WXMOTIF__)
1261 // the checkbox without label still has some space to the right in wxGTK,
1262 // so shift it to the right
1263 size.x -= 8;
1264#elif defined(__WXMSW__)
1265 // here too, but in other way
1266 size.x += 1;
1267 size.y -= 2;
1268#endif
1269
1270 int hAlign = wxALIGN_CENTRE;
1271 int vAlign = wxALIGN_CENTRE;
1272 if (GetCellAttr())
1273 GetCellAttr()->GetAlignment(& hAlign, & vAlign);
1274
1275 int x = 0, y = 0;
1276 if (hAlign == wxALIGN_LEFT)
1277 {
1278 x = r.x + 2;
1279#ifdef __WXMSW__
1280 x += 2;
1281#endif
1282 y = r.y + r.height/2 - size.y/2;
1283 }
1284 else if (hAlign == wxALIGN_RIGHT)
1285 {
1286 x = r.x + r.width - size.x - 2;
1287 y = r.y + r.height/2 - size.y/2;
1288 }
1289 else if (hAlign == wxALIGN_CENTRE)
1290 {
1291 x = r.x + r.width/2 - size.x/2;
1292 y = r.y + r.height/2 - size.y/2;
1293 }
1294
1295 m_control->Move(x, y);
1296}
1297
1298void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
1299{
1300 m_control->Show(show);
1301
1302 if ( show )
1303 {
1304 wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
1305 CBox()->SetBackgroundColour(colBg);
1306 }
1307}
1308
1309void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
1310{
1311 wxASSERT_MSG(m_control,
1312 wxT("The wxGridCellEditor must be Created first!"));
1313
1314 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
1315 m_startValue = grid->GetTable()->GetValueAsBool(row, col);
1316 else
1317 {
1318 wxString cellval( grid->GetTable()->GetValue(row, col) );
1319 m_startValue = !( !cellval || (cellval == wxT("0")) );
1320 }
1321 CBox()->SetValue(m_startValue);
1322 CBox()->SetFocus();
1323}
1324
1325bool wxGridCellBoolEditor::EndEdit(int row, int col,
1326 wxGrid* grid)
1327{
1328 wxASSERT_MSG(m_control,
1329 wxT("The wxGridCellEditor must be Created first!"));
1330
1331 bool changed = false;
1332 bool value = CBox()->GetValue();
1333 if ( value != m_startValue )
1334 changed = true;
1335
1336 if ( changed )
1337 {
1338 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
1339 grid->GetTable()->SetValueAsBool(row, col, value);
1340 else
1341 grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
1342 }
1343
1344 return changed;
1345}
1346
1347void wxGridCellBoolEditor::Reset()
1348{
1349 wxASSERT_MSG(m_control,
1350 wxT("The wxGridCellEditor must be Created first!"));
1351
1352 CBox()->SetValue(m_startValue);
1353}
1354
1355void wxGridCellBoolEditor::StartingClick()
1356{
1357 CBox()->SetValue(!CBox()->GetValue());
1358}
1359
1360bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event)
1361{
1362 if ( wxGridCellEditor::IsAcceptedKey(event) )
1363 {
1364 int keycode = event.GetKeyCode();
1365 switch ( keycode )
1366 {
1367 case WXK_SPACE:
1368 case '+':
1369 case '-':
1370 return true;
1371 }
1372 }
1373
1374 return false;
1375}
1376
1377void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event)
1378{
1379 int keycode = event.GetKeyCode();
1380 switch ( keycode )
1381 {
1382 case WXK_SPACE:
1383 CBox()->SetValue(!CBox()->GetValue());
1384 break;
1385
1386 case '+':
1387 CBox()->SetValue(true);
1388 break;
1389
1390 case '-':
1391 CBox()->SetValue(false);
1392 break;
1393 }
1394}
1395
1396
1397// return the value as "1" for true and the empty string for false
1398wxString wxGridCellBoolEditor::GetValue() const
1399{
1400 bool bSet = CBox()->GetValue();
1401 return bSet ? _T("1") : wxEmptyString;
1402}
1403
1404#endif // wxUSE_CHECKBOX
1405
1406#if wxUSE_COMBOBOX
1407
1408// ----------------------------------------------------------------------------
1409// wxGridCellChoiceEditor
1410// ----------------------------------------------------------------------------
1411
1412wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString& choices,
1413 bool allowOthers)
1414 : m_choices(choices),
1415 m_allowOthers(allowOthers) { }
1416
1417wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
1418 const wxString choices[],
1419 bool allowOthers)
1420 : m_allowOthers(allowOthers)
1421{
1422 if ( count )
1423 {
1424 m_choices.Alloc(count);
1425 for ( size_t n = 0; n < count; n++ )
1426 {
1427 m_choices.Add(choices[n]);
1428 }
1429 }
1430}
1431
1432wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
1433{
1434 wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
1435 editor->m_allowOthers = m_allowOthers;
1436 editor->m_choices = m_choices;
1437
1438 return editor;
1439}
1440
1441void wxGridCellChoiceEditor::Create(wxWindow* parent,
1442 wxWindowID id,
1443 wxEvtHandler* evtHandler)
1444{
1445 m_control = new wxComboBox(parent, id, wxEmptyString,
1446 wxDefaultPosition, wxDefaultSize,
1447 m_choices,
1448 m_allowOthers ? 0 : wxCB_READONLY);
1449
1450 wxGridCellEditor::Create(parent, id, evtHandler);
1451}
1452
1453void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
1454 wxGridCellAttr * attr)
1455{
1456 // as we fill the entire client area, don't do anything here to minimize
1457 // flicker
1458
1459 // TODO: It doesn't actually fill the client area since the height of a
1460 // combo always defaults to the standard... Until someone has time to
1461 // figure out the right rectangle to paint, just do it the normal way...
1462 wxGridCellEditor::PaintBackground(rectCell, attr);
1463}
1464
1465void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
1466{
1467 wxASSERT_MSG(m_control,
1468 wxT("The wxGridCellEditor must be Created first!"));
1469
1470 wxGridCellEditorEvtHandler* evtHandler = NULL;
1471 if (m_control)
1472 evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
1473
1474 // Don't immediately end if we get a kill focus event within BeginEdit
1475 if (evtHandler)
1476 evtHandler->SetInSetFocus(true);
1477
1478 m_startValue = grid->GetTable()->GetValue(row, col);
1479
1480 if (m_allowOthers)
1481 Combo()->SetValue(m_startValue);
1482 else
1483 {
1484 // find the right position, or default to the first if not found
1485 int pos = Combo()->FindString(m_startValue);
1486 if (pos == wxNOT_FOUND)
1487 pos = 0;
1488 Combo()->SetSelection(pos);
1489 }
1490 Combo()->SetInsertionPointEnd();
1491 Combo()->SetFocus();
1492
1493 if (evtHandler)
1494 evtHandler->SetInSetFocus(false);
1495}
1496
1497bool wxGridCellChoiceEditor::EndEdit(int row, int col,
1498 wxGrid* grid)
1499{
1500 wxString value = Combo()->GetValue();
1501 if ( value == m_startValue )
1502 return false;
1503
1504 grid->GetTable()->SetValue(row, col, value);
1505
1506 return true;
1507}
1508
1509void wxGridCellChoiceEditor::Reset()
1510{
1511 Combo()->SetValue(m_startValue);
1512 Combo()->SetInsertionPointEnd();
1513}
1514
1515void wxGridCellChoiceEditor::SetParameters(const wxString& params)
1516{
1517 if ( !params )
1518 {
1519 // what can we do?
1520 return;
1521 }
1522
1523 m_choices.Empty();
1524
1525 wxStringTokenizer tk(params, _T(','));
1526 while ( tk.HasMoreTokens() )
1527 {
1528 m_choices.Add(tk.GetNextToken());
1529 }
1530}
1531
1532// return the value in the text control
1533wxString wxGridCellChoiceEditor::GetValue() const
1534{
1535 return Combo()->GetValue();
1536}
1537
1538#endif // wxUSE_COMBOBOX
1539
1540// ----------------------------------------------------------------------------
1541// wxGridCellEditorEvtHandler
1542// ----------------------------------------------------------------------------
1543
1544void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent& event)
1545{
1546 // Don't disable the cell if we're just starting to edit it
1547 if (m_inSetFocus)
1548 return;
1549
1550 // accept changes
1551 m_grid->DisableCellEditControl();
1552
1553 event.Skip();
1554}
1555
1556void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
1557{
1558 switch ( event.GetKeyCode() )
1559 {
1560 case WXK_ESCAPE:
1561 m_editor->Reset();
1562 m_grid->DisableCellEditControl();
1563 break;
1564
1565 case WXK_TAB:
1566 m_grid->GetEventHandler()->ProcessEvent( event );
1567 break;
1568
1569 case WXK_RETURN:
1570 case WXK_NUMPAD_ENTER:
1571 if (!m_grid->GetEventHandler()->ProcessEvent(event))
1572 m_editor->HandleReturn(event);
1573 break;
1574
1575 default:
1576 event.Skip();
1577 }
1578}
1579
1580void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
1581{
1582 switch ( event.GetKeyCode() )
1583 {
1584 case WXK_ESCAPE:
1585 case WXK_TAB:
1586 case WXK_RETURN:
1587 case WXK_NUMPAD_ENTER:
1588 break;
1589
1590 default:
1591 event.Skip();
1592 }
1593}
1594
1595// ----------------------------------------------------------------------------
1596// wxGridCellWorker is an (almost) empty common base class for
1597// wxGridCellRenderer and wxGridCellEditor managing ref counting
1598// ----------------------------------------------------------------------------
1599
1600void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params))
1601{
1602 // nothing to do
1603}
1604
1605wxGridCellWorker::~wxGridCellWorker()
1606{
1607}
1608
1609// ============================================================================
1610// renderer classes
1611// ============================================================================
1612
1613// ----------------------------------------------------------------------------
1614// wxGridCellRenderer
1615// ----------------------------------------------------------------------------
1616
1617void wxGridCellRenderer::Draw(wxGrid& grid,
1618 wxGridCellAttr& attr,
1619 wxDC& dc,
1620 const wxRect& rect,
1621 int WXUNUSED(row), int WXUNUSED(col),
1622 bool isSelected)
1623{
1624 dc.SetBackgroundMode( wxSOLID );
1625
1626 // grey out fields if the grid is disabled
1627 if( grid.IsEnabled() )
1628 {
1629 if ( isSelected )
1630 {
1631 dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
1632 }
1633 else
1634 {
1635 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
1636 }
1637 }
1638 else
1639 {
1640 dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID));
1641 }
1642
1643 dc.SetPen( *wxTRANSPARENT_PEN );
1644 dc.DrawRectangle(rect);
1645}
1646
1647// ----------------------------------------------------------------------------
1648// wxGridCellStringRenderer
1649// ----------------------------------------------------------------------------
1650
1651void wxGridCellStringRenderer::SetTextColoursAndFont(wxGrid& grid,
1652 wxGridCellAttr& attr,
1653 wxDC& dc,
1654 bool isSelected)
1655{
1656 dc.SetBackgroundMode( wxTRANSPARENT );
1657
1658 // TODO some special colours for attr.IsReadOnly() case?
1659
1660 // different coloured text when the grid is disabled
1661 if( grid.IsEnabled() )
1662 {
1663 if ( isSelected )
1664 {
1665 dc.SetTextBackground( grid.GetSelectionBackground() );
1666 dc.SetTextForeground( grid.GetSelectionForeground() );
1667 }
1668 else
1669 {
1670 dc.SetTextBackground( attr.GetBackgroundColour() );
1671 dc.SetTextForeground( attr.GetTextColour() );
1672 }
1673 }
1674 else
1675 {
1676 dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
1677 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
1678 }
1679
1680 dc.SetFont( attr.GetFont() );
1681}
1682
1683wxSize wxGridCellStringRenderer::DoGetBestSize(wxGridCellAttr& attr,
1684 wxDC& dc,
1685 const wxString& text)
1686{
1687 wxCoord x = 0, y = 0, max_x = 0;
1688 dc.SetFont(attr.GetFont());
1689 wxStringTokenizer tk(text, _T('\n'));
1690 while ( tk.HasMoreTokens() )
1691 {
1692 dc.GetTextExtent(tk.GetNextToken(), &x, &y);
1693 max_x = wxMax(max_x, x);
1694 }
1695
1696 y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
1697
1698 return wxSize(max_x, y);
1699}
1700
1701wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
1702 wxGridCellAttr& attr,
1703 wxDC& dc,
1704 int row, int col)
1705{
1706 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
1707}
1708
1709void wxGridCellStringRenderer::Draw(wxGrid& grid,
1710 wxGridCellAttr& attr,
1711 wxDC& dc,
1712 const wxRect& rectCell,
1713 int row, int col,
1714 bool isSelected)
1715{
1716 wxRect rect = rectCell;
1717 rect.Inflate(-1);
1718
1719 // erase only this cells background, overflow cells should have been erased
1720 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1721
1722 int hAlign, vAlign;
1723 attr.GetAlignment(&hAlign, &vAlign);
1724
1725 int overflowCols = 0;
1726
1727 if (attr.GetOverflow())
1728 {
1729 int cols = grid.GetNumberCols();
1730 int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
1731 int cell_rows, cell_cols;
1732 attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <=0
1733 if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
1734 {
1735 int i, c_cols, c_rows;
1736 for (i = col+cell_cols; i < cols; i++)
1737 {
1738 bool is_empty = true;
1739 for (int j=row; j<row+cell_rows; j++)
1740 {
1741 // check w/ anchor cell for multicell block
1742 grid.GetCellSize(j, i, &c_rows, &c_cols);
1743 if (c_rows > 0) c_rows = 0;
1744 if (!grid.GetTable()->IsEmptyCell(j+c_rows, i))
1745 {
1746 is_empty = false;
1747 break;
1748 }
1749 }
1750 if (is_empty)
1751 rect.width += grid.GetColSize(i);
1752 else
1753 {
1754 i--;
1755 break;
1756 }
1757 if (rect.width >= best_width) break;
1758 }
1759 overflowCols = i - col - cell_cols + 1;
1760 if (overflowCols >= cols) overflowCols = cols - 1;
1761 }
1762
1763 if (overflowCols > 0) // redraw overflow cells w/ proper hilight
1764 {
1765 hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
1766 wxRect clip = rect;
1767 clip.x += rectCell.width;
1768 // draw each overflow cell individually
1769 int col_end = col+cell_cols+overflowCols;
1770 if (col_end >= grid.GetNumberCols())
1771 col_end = grid.GetNumberCols() - 1;
1772 for (int i = col+cell_cols; i <= col_end; i++)
1773 {
1774 clip.width = grid.GetColSize(i) - 1;
1775 dc.DestroyClippingRegion();
1776 dc.SetClippingRegion(clip);
1777
1778 SetTextColoursAndFont(grid, attr, dc,
1779 grid.IsInSelection(row,i));
1780
1781 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
1782 rect, hAlign, vAlign);
1783 clip.x += grid.GetColSize(i) - 1;
1784 }
1785
1786 rect = rectCell;
1787 rect.Inflate(-1);
1788 rect.width++;
1789 dc.DestroyClippingRegion();
1790 }
1791 }
1792
1793 // now we only have to draw the text
1794 SetTextColoursAndFont(grid, attr, dc, isSelected);
1795
1796 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
1797 rect, hAlign, vAlign);
1798}
1799
1800// ----------------------------------------------------------------------------
1801// wxGridCellNumberRenderer
1802// ----------------------------------------------------------------------------
1803
1804wxString wxGridCellNumberRenderer::GetString(wxGrid& grid, int row, int col)
1805{
1806 wxGridTableBase *table = grid.GetTable();
1807 wxString text;
1808 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
1809 {
1810 text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
1811 }
1812 else
1813 {
1814 text = table->GetValue(row, col);
1815 }
1816
1817 return text;
1818}
1819
1820void wxGridCellNumberRenderer::Draw(wxGrid& grid,
1821 wxGridCellAttr& attr,
1822 wxDC& dc,
1823 const wxRect& rectCell,
1824 int row, int col,
1825 bool isSelected)
1826{
1827 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1828
1829 SetTextColoursAndFont(grid, attr, dc, isSelected);
1830
1831 // draw the text right aligned by default
1832 int hAlign, vAlign;
1833 attr.GetAlignment(&hAlign, &vAlign);
1834 hAlign = wxALIGN_RIGHT;
1835
1836 wxRect rect = rectCell;
1837 rect.Inflate(-1);
1838
1839 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1840}
1841
1842wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
1843 wxGridCellAttr& attr,
1844 wxDC& dc,
1845 int row, int col)
1846{
1847 return DoGetBestSize(attr, dc, GetString(grid, row, col));
1848}
1849
1850// ----------------------------------------------------------------------------
1851// wxGridCellFloatRenderer
1852// ----------------------------------------------------------------------------
1853
1854wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
1855{
1856 SetWidth(width);
1857 SetPrecision(precision);
1858}
1859
1860wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
1861{
1862 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
1863 renderer->m_width = m_width;
1864 renderer->m_precision = m_precision;
1865 renderer->m_format = m_format;
1866
1867 return renderer;
1868}
1869
1870wxString wxGridCellFloatRenderer::GetString(wxGrid& grid, int row, int col)
1871{
1872 wxGridTableBase *table = grid.GetTable();
1873
1874 bool hasDouble;
1875 double val;
1876 wxString text;
1877 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1878 {
1879 val = table->GetValueAsDouble(row, col);
1880 hasDouble = true;
1881 }
1882 else
1883 {
1884 text = table->GetValue(row, col);
1885 hasDouble = text.ToDouble(&val);
1886 }
1887
1888 if ( hasDouble )
1889 {
1890 if ( !m_format )
1891 {
1892 if ( m_width == -1 )
1893 {
1894 if ( m_precision == -1 )
1895 {
1896 // default width/precision
1897 m_format = _T("%f");
1898 }
1899 else
1900 {
1901 m_format.Printf(_T("%%.%df"), m_precision);
1902 }
1903 }
1904 else if ( m_precision == -1 )
1905 {
1906 // default precision
1907 m_format.Printf(_T("%%%d.f"), m_width);
1908 }
1909 else
1910 {
1911 m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
1912 }
1913 }
1914
1915 text.Printf(m_format, val);
1916
1917 }
1918 //else: text already contains the string
1919
1920 return text;
1921}
1922
1923void wxGridCellFloatRenderer::Draw(wxGrid& grid,
1924 wxGridCellAttr& attr,
1925 wxDC& dc,
1926 const wxRect& rectCell,
1927 int row, int col,
1928 bool isSelected)
1929{
1930 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1931
1932 SetTextColoursAndFont(grid, attr, dc, isSelected);
1933
1934 // draw the text right aligned by default
1935 int hAlign, vAlign;
1936 attr.GetAlignment(&hAlign, &vAlign);
1937 hAlign = wxALIGN_RIGHT;
1938
1939 wxRect rect = rectCell;
1940 rect.Inflate(-1);
1941
1942 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1943}
1944
1945wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
1946 wxGridCellAttr& attr,
1947 wxDC& dc,
1948 int row, int col)
1949{
1950 return DoGetBestSize(attr, dc, GetString(grid, row, col));
1951}
1952
1953void wxGridCellFloatRenderer::SetParameters(const wxString& params)
1954{
1955 if ( !params )
1956 {
1957 // reset to defaults
1958 SetWidth(-1);
1959 SetPrecision(-1);
1960 }
1961 else
1962 {
1963 wxString tmp = params.BeforeFirst(_T(','));
1964 if ( !tmp.empty() )
1965 {
1966 long width;
1967 if ( tmp.ToLong(&width) )
1968 {
1969 SetWidth((int)width);
1970 }
1971 else
1972 {
1973 wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
1974 }
1975
1976 }
1977 tmp = params.AfterFirst(_T(','));
1978 if ( !tmp.empty() )
1979 {
1980 long precision;
1981 if ( tmp.ToLong(&precision) )
1982 {
1983 SetPrecision((int)precision);
1984 }
1985 else
1986 {
1987 wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
1988 }
1989
1990 }
1991 }
1992}
1993
1994
1995// ----------------------------------------------------------------------------
1996// wxGridCellBoolRenderer
1997// ----------------------------------------------------------------------------
1998
1999wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
2000
2001// FIXME these checkbox size calculations are really ugly...
2002
2003// between checkmark and box
2004static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
2005
2006wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
2007 wxGridCellAttr& WXUNUSED(attr),
2008 wxDC& WXUNUSED(dc),
2009 int WXUNUSED(row),
2010 int WXUNUSED(col))
2011{
2012 // compute it only once (no locks for MT safeness in GUI thread...)
2013 if ( !ms_sizeCheckMark.x )
2014 {
2015 // get checkbox size
2016 wxCheckBox *checkbox = new wxCheckBox(&grid, wxID_ANY, wxEmptyString);
2017 wxSize size = checkbox->GetBestSize();
2018 wxCoord checkSize = size.y + 2*wxGRID_CHECKMARK_MARGIN;
2019
2020 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
2021#if defined(__WXGTK__) || defined(__WXMOTIF__)
2022 checkSize -= size.y / 2;
2023#endif
2024
2025 delete checkbox;
2026
2027 ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
2028 }
2029
2030 return ms_sizeCheckMark;
2031}
2032
2033void wxGridCellBoolRenderer::Draw(wxGrid& grid,
2034 wxGridCellAttr& attr,
2035 wxDC& dc,
2036 const wxRect& rect,
2037 int row, int col,
2038 bool isSelected)
2039{
2040 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
2041
2042 // draw a check mark in the centre (ignoring alignment - TODO)
2043 wxSize size = GetBestSize(grid, attr, dc, row, col);
2044
2045 // don't draw outside the cell
2046 wxCoord minSize = wxMin(rect.width, rect.height);
2047 if ( size.x >= minSize || size.y >= minSize )
2048 {
2049 // and even leave (at least) 1 pixel margin
2050 size.x = size.y = minSize - 2;
2051 }
2052
2053 // draw a border around checkmark
2054 int vAlign, hAlign;
2055 attr.GetAlignment(& hAlign, &vAlign);
2056
2057 wxRect rectBorder;
2058 if (hAlign == wxALIGN_CENTRE)
2059 {
2060 rectBorder.x = rect.x + rect.width/2 - size.x/2;
2061 rectBorder.y = rect.y + rect.height/2 - size.y/2;
2062 rectBorder.width = size.x;
2063 rectBorder.height = size.y;
2064 }
2065 else if (hAlign == wxALIGN_LEFT)
2066 {
2067 rectBorder.x = rect.x + 2;
2068 rectBorder.y = rect.y + rect.height/2 - size.y/2;
2069 rectBorder.width = size.x;
2070 rectBorder.height = size.y;
2071 }
2072 else if (hAlign == wxALIGN_RIGHT)
2073 {
2074 rectBorder.x = rect.x + rect.width - size.x - 2;
2075 rectBorder.y = rect.y + rect.height/2 - size.y/2;
2076 rectBorder.width = size.x;
2077 rectBorder.height = size.y;
2078 }
2079
2080 bool value;
2081 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
2082 value = grid.GetTable()->GetValueAsBool(row, col);
2083 else
2084 {
2085 wxString cellval( grid.GetTable()->GetValue(row, col) );
2086 value = !( !cellval || (cellval == wxT("0")) );
2087 }
2088
2089 if ( value )
2090 {
2091 wxRect rectMark = rectBorder;
2092#ifdef __WXMSW__
2093 // MSW DrawCheckMark() is weird (and should probably be changed...)
2094 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN/2);
2095 rectMark.x++;
2096 rectMark.y++;
2097#else // !MSW
2098 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
2099#endif // MSW/!MSW
2100
2101 dc.SetTextForeground(attr.GetTextColour());
2102 dc.DrawCheckMark(rectMark);
2103 }
2104
2105 dc.SetBrush(*wxTRANSPARENT_BRUSH);
2106 dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
2107 dc.DrawRectangle(rectBorder);
2108}
2109
2110// ----------------------------------------------------------------------------
2111// wxGridCellAttr
2112// ----------------------------------------------------------------------------
2113
2114void wxGridCellAttr::Init(wxGridCellAttr *attrDefault)
2115{
2116 m_nRef = 1;
2117
2118 m_isReadOnly = Unset;
2119
2120 m_renderer = NULL;
2121 m_editor = NULL;
2122
2123 m_attrkind = wxGridCellAttr::Cell;
2124
2125 m_sizeRows = m_sizeCols = 1;
2126 m_overflow = UnsetOverflow;
2127
2128 SetDefAttr(attrDefault);
2129}
2130
2131wxGridCellAttr *wxGridCellAttr::Clone() const
2132{
2133 wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr);
2134
2135 if ( HasTextColour() )
2136 attr->SetTextColour(GetTextColour());
2137 if ( HasBackgroundColour() )
2138 attr->SetBackgroundColour(GetBackgroundColour());
2139 if ( HasFont() )
2140 attr->SetFont(GetFont());
2141 if ( HasAlignment() )
2142 attr->SetAlignment(m_hAlign, m_vAlign);
2143
2144 attr->SetSize( m_sizeRows, m_sizeCols );
2145
2146 if ( m_renderer )
2147 {
2148 attr->SetRenderer(m_renderer);
2149 m_renderer->IncRef();
2150 }
2151 if ( m_editor )
2152 {
2153 attr->SetEditor(m_editor);
2154 m_editor->IncRef();
2155 }
2156
2157 if ( IsReadOnly() )
2158 attr->SetReadOnly();
2159
2160 attr->SetKind( m_attrkind );
2161
2162 return attr;
2163}
2164
2165void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom)
2166{
2167 if ( !HasTextColour() && mergefrom->HasTextColour() )
2168 SetTextColour(mergefrom->GetTextColour());
2169 if ( !HasBackgroundColour() && mergefrom->HasBackgroundColour() )
2170 SetBackgroundColour(mergefrom->GetBackgroundColour());
2171 if ( !HasFont() && mergefrom->HasFont() )
2172 SetFont(mergefrom->GetFont());
2173 if ( !HasAlignment() && mergefrom->HasAlignment() ){
2174 int hAlign, vAlign;
2175 mergefrom->GetAlignment( &hAlign, &vAlign);
2176 SetAlignment(hAlign, vAlign);
2177 }
2178 if ( !HasSize() && mergefrom->HasSize() )
2179 mergefrom->GetSize( &m_sizeRows, &m_sizeCols );
2180
2181 // Directly access member functions as GetRender/Editor don't just return
2182 // m_renderer/m_editor
2183 //
2184 // Maybe add support for merge of Render and Editor?
2185 if (!HasRenderer() && mergefrom->HasRenderer() )
2186 {
2187 m_renderer = mergefrom->m_renderer;
2188 m_renderer->IncRef();
2189 }
2190 if ( !HasEditor() && mergefrom->HasEditor() )
2191 {
2192 m_editor = mergefrom->m_editor;
2193 m_editor->IncRef();
2194 }
2195 if ( !HasReadWriteMode() && mergefrom->HasReadWriteMode() )
2196 SetReadOnly(mergefrom->IsReadOnly());
2197
2198 if (!HasOverflowMode() && mergefrom->HasOverflowMode() )
2199 SetOverflow(mergefrom->GetOverflow());
2200
2201 SetDefAttr(mergefrom->m_defGridAttr);
2202}
2203
2204void wxGridCellAttr::SetSize(int num_rows, int num_cols)
2205{
2206 // The size of a cell is normally 1,1
2207
2208 // If this cell is larger (2,2) then this is the top left cell
2209 // the other cells that will be covered (lower right cells) must be
2210 // set to negative or zero values such that
2211 // row + num_rows of the covered cell points to the larger cell (this cell)
2212 // same goes for the col + num_cols.
2213
2214 // Size of 0,0 is NOT valid, neither is <=0 and any positive value
2215
2216 wxASSERT_MSG( (!((num_rows>0)&&(num_cols<=0)) ||
2217 !((num_rows<=0)&&(num_cols>0)) ||
2218 !((num_rows==0)&&(num_cols==0))),
2219 wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values"));
2220
2221 m_sizeRows = num_rows;
2222 m_sizeCols = num_cols;
2223}
2224
2225const wxColour& wxGridCellAttr::GetTextColour() const
2226{
2227 if (HasTextColour())
2228 {
2229 return m_colText;
2230 }
2231 else if (m_defGridAttr && m_defGridAttr != this)
2232 {
2233 return m_defGridAttr->GetTextColour();
2234 }
2235 else
2236 {
2237 wxFAIL_MSG(wxT("Missing default cell attribute"));
2238 return wxNullColour;
2239 }
2240}
2241
2242
2243const wxColour& wxGridCellAttr::GetBackgroundColour() const
2244{
2245 if (HasBackgroundColour())
2246 return m_colBack;
2247 else if (m_defGridAttr && m_defGridAttr != this)
2248 return m_defGridAttr->GetBackgroundColour();
2249 else
2250 {
2251 wxFAIL_MSG(wxT("Missing default cell attribute"));
2252 return wxNullColour;
2253 }
2254}
2255
2256
2257const wxFont& wxGridCellAttr::GetFont() const
2258{
2259 if (HasFont())
2260 return m_font;
2261 else if (m_defGridAttr && m_defGridAttr != this)
2262 return m_defGridAttr->GetFont();
2263 else
2264 {
2265 wxFAIL_MSG(wxT("Missing default cell attribute"));
2266 return wxNullFont;
2267 }
2268}
2269
2270
2271void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
2272{
2273 if (HasAlignment())
2274 {
2275 if ( hAlign ) *hAlign = m_hAlign;
2276 if ( vAlign ) *vAlign = m_vAlign;
2277 }
2278 else if (m_defGridAttr && m_defGridAttr != this)
2279 m_defGridAttr->GetAlignment(hAlign, vAlign);
2280 else
2281 {
2282 wxFAIL_MSG(wxT("Missing default cell attribute"));
2283 }
2284}
2285
2286void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const
2287{
2288 if ( num_rows ) *num_rows = m_sizeRows;
2289 if ( num_cols ) *num_cols = m_sizeCols;
2290}
2291
2292// GetRenderer and GetEditor use a slightly different decision path about
2293// which attribute to use. If a non-default attr object has one then it is
2294// used, otherwise the default editor or renderer is fetched from the grid and
2295// used. It should be the default for the data type of the cell. If it is
2296// NULL (because the table has a type that the grid does not have in its
2297// registry,) then the grid's default editor or renderer is used.
2298
2299wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
2300{
2301 wxGridCellRenderer *renderer;
2302
2303 if ( m_renderer && this != m_defGridAttr )
2304 {
2305 // use the cells renderer if it has one
2306 renderer = m_renderer;
2307 renderer->IncRef();
2308 }
2309 else // no non default cell renderer
2310 {
2311 // get default renderer for the data type
2312 if ( grid )
2313 {
2314 // GetDefaultRendererForCell() will do IncRef() for us
2315 renderer = grid->GetDefaultRendererForCell(row, col);
2316 }
2317 else
2318 {
2319 renderer = NULL;
2320 }
2321
2322 if ( !renderer )
2323 {
2324 if (m_defGridAttr && this != m_defGridAttr )
2325 {
2326 // if we still don't have one then use the grid default
2327 // (no need for IncRef() here neither)
2328 renderer = m_defGridAttr->GetRenderer(NULL, 0, 0);
2329 }
2330 else // default grid attr
2331 {
2332 // use m_renderer which we had decided not to use initially
2333 renderer = m_renderer;
2334 if ( renderer )
2335 renderer->IncRef();
2336 }
2337 }
2338 }
2339
2340 // we're supposed to always find something
2341 wxASSERT_MSG(renderer, wxT("Missing default cell renderer"));
2342
2343 return renderer;
2344}
2345
2346// same as above, except for s/renderer/editor/g
2347wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
2348{
2349 wxGridCellEditor *editor;
2350
2351 if ( m_editor && this != m_defGridAttr )
2352 {
2353 // use the cells editor if it has one
2354 editor = m_editor;
2355 editor->IncRef();
2356 }
2357 else // no non default cell editor
2358 {
2359 // get default editor for the data type
2360 if ( grid )
2361 {
2362 // GetDefaultEditorForCell() will do IncRef() for us
2363 editor = grid->GetDefaultEditorForCell(row, col);
2364 }
2365 else
2366 {
2367 editor = NULL;
2368 }
2369
2370 if ( !editor )
2371 {
2372 if ( m_defGridAttr && this != m_defGridAttr )
2373 {
2374 // if we still don't have one then use the grid default
2375 // (no need for IncRef() here neither)
2376 editor = m_defGridAttr->GetEditor(NULL, 0, 0);
2377 }
2378 else // default grid attr
2379 {
2380 // use m_editor which we had decided not to use initially
2381 editor = m_editor;
2382 if ( editor )
2383 editor->IncRef();
2384 }
2385 }
2386 }
2387
2388 // we're supposed to always find something
2389 wxASSERT_MSG(editor, wxT("Missing default cell editor"));
2390
2391 return editor;
2392}
2393
2394// ----------------------------------------------------------------------------
2395// wxGridCellAttrData
2396// ----------------------------------------------------------------------------
2397
2398void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
2399{
2400 int n = FindIndex(row, col);
2401 if ( n == wxNOT_FOUND )
2402 {
2403 // add the attribute
2404 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
2405 }
2406 else
2407 {
2408 // free the old attribute
2409 m_attrs[(size_t)n].attr->DecRef();
2410
2411 if ( attr )
2412 {
2413 // change the attribute
2414 m_attrs[(size_t)n].attr = attr;
2415 }
2416 else
2417 {
2418 // remove this attribute
2419 m_attrs.RemoveAt((size_t)n);
2420 }
2421 }
2422}
2423
2424wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
2425{
2426 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2427
2428 int n = FindIndex(row, col);
2429 if ( n != wxNOT_FOUND )
2430 {
2431 attr = m_attrs[(size_t)n].attr;
2432 attr->IncRef();
2433 }
2434
2435 return attr;
2436}
2437
2438void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
2439{
2440 size_t count = m_attrs.GetCount();
2441 for ( size_t n = 0; n < count; n++ )
2442 {
2443 wxGridCellCoords& coords = m_attrs[n].coords;
2444 wxCoord row = coords.GetRow();
2445 if ((size_t)row >= pos)
2446 {
2447 if (numRows > 0)
2448 {
2449 // If rows inserted, include row counter where necessary
2450 coords.SetRow(row + numRows);
2451 }
2452 else if (numRows < 0)
2453 {
2454 // If rows deleted ...
2455 if ((size_t)row >= pos - numRows)
2456 {
2457 // ...either decrement row counter (if row still exists)...
2458 coords.SetRow(row + numRows);
2459 }
2460 else
2461 {
2462 // ...or remove the attribute
2463 // No need to DecRef the attribute itself since this is
2464 // done be wxGridCellWithAttr's destructor!
2465 m_attrs.RemoveAt(n);
2466 n--; count--;
2467 }
2468 }
2469 }
2470 }
2471}
2472
2473void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
2474{
2475 size_t count = m_attrs.GetCount();
2476 for ( size_t n = 0; n < count; n++ )
2477 {
2478 wxGridCellCoords& coords = m_attrs[n].coords;
2479 wxCoord col = coords.GetCol();
2480 if ( (size_t)col >= pos )
2481 {
2482 if ( numCols > 0 )
2483 {
2484 // If rows inserted, include row counter where necessary
2485 coords.SetCol(col + numCols);
2486 }
2487 else if (numCols < 0)
2488 {
2489 // If rows deleted ...
2490 if ((size_t)col >= pos - numCols)
2491 {
2492 // ...either decrement row counter (if row still exists)...
2493 coords.SetCol(col + numCols);
2494 }
2495 else
2496 {
2497 // ...or remove the attribute
2498 // No need to DecRef the attribute itself since this is
2499 // done be wxGridCellWithAttr's destructor!
2500 m_attrs.RemoveAt(n);
2501 n--; count--;
2502 }
2503 }
2504 }
2505 }
2506}
2507
2508int wxGridCellAttrData::FindIndex(int row, int col) const
2509{
2510 size_t count = m_attrs.GetCount();
2511 for ( size_t n = 0; n < count; n++ )
2512 {
2513 const wxGridCellCoords& coords = m_attrs[n].coords;
2514 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
2515 {
2516 return n;
2517 }
2518 }
2519
2520 return wxNOT_FOUND;
2521}
2522
2523// ----------------------------------------------------------------------------
2524// wxGridRowOrColAttrData
2525// ----------------------------------------------------------------------------
2526
2527wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
2528{
2529 size_t count = m_attrs.Count();
2530 for ( size_t n = 0; n < count; n++ )
2531 {
2532 m_attrs[n]->DecRef();
2533 }
2534}
2535
2536wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
2537{
2538 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2539
2540 int n = m_rowsOrCols.Index(rowOrCol);
2541 if ( n != wxNOT_FOUND )
2542 {
2543 attr = m_attrs[(size_t)n];
2544 attr->IncRef();
2545 }
2546
2547 return attr;
2548}
2549
2550void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
2551{
2552 int i = m_rowsOrCols.Index(rowOrCol);
2553 if ( i == wxNOT_FOUND )
2554 {
2555 // add the attribute
2556 m_rowsOrCols.Add(rowOrCol);
2557 m_attrs.Add(attr);
2558 }
2559 else
2560 {
2561 size_t n = (size_t)i;
2562 if ( attr )
2563 {
2564 // change the attribute
2565 m_attrs[n]->DecRef();
2566 m_attrs[n] = attr;
2567 }
2568 else
2569 {
2570 // remove this attribute
2571 m_attrs[n]->DecRef();
2572 m_rowsOrCols.RemoveAt(n);
2573 m_attrs.RemoveAt(n);
2574 }
2575 }
2576}
2577
2578void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
2579{
2580 size_t count = m_attrs.GetCount();
2581 for ( size_t n = 0; n < count; n++ )
2582 {
2583 int & rowOrCol = m_rowsOrCols[n];
2584 if ( (size_t)rowOrCol >= pos )
2585 {
2586 if ( numRowsOrCols > 0 )
2587 {
2588 // If rows inserted, include row counter where necessary
2589 rowOrCol += numRowsOrCols;
2590 }
2591 else if ( numRowsOrCols < 0)
2592 {
2593 // If rows deleted, either decrement row counter (if row still exists)
2594 if ((size_t)rowOrCol >= pos - numRowsOrCols)
2595 rowOrCol += numRowsOrCols;
2596 else
2597 {
2598 m_rowsOrCols.RemoveAt(n);
2599 m_attrs[n]->DecRef();
2600 m_attrs.RemoveAt(n);
2601 n--; count--;
2602 }
2603 }
2604 }
2605 }
2606}
2607
2608// ----------------------------------------------------------------------------
2609// wxGridCellAttrProvider
2610// ----------------------------------------------------------------------------
2611
2612wxGridCellAttrProvider::wxGridCellAttrProvider()
2613{
2614 m_data = (wxGridCellAttrProviderData *)NULL;
2615}
2616
2617wxGridCellAttrProvider::~wxGridCellAttrProvider()
2618{
2619 delete m_data;
2620}
2621
2622void wxGridCellAttrProvider::InitData()
2623{
2624 m_data = new wxGridCellAttrProviderData;
2625}
2626
2627wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col,
2628 wxGridCellAttr::wxAttrKind kind ) const
2629{
2630 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2631 if ( m_data )
2632 {
2633 switch(kind)
2634 {
2635 case (wxGridCellAttr::Any):
2636 //Get cached merge attributes.
2637 // Currenlty not used as no cache implemented as not mutiable
2638 // attr = m_data->m_mergeAttr.GetAttr(row, col);
2639 if(!attr)
2640 {
2641 //Basicaly implement old version.
2642 //Also check merge cache, so we don't have to re-merge every time..
2643 wxGridCellAttr *attrcell = m_data->m_cellAttrs.GetAttr(row, col);
2644 wxGridCellAttr *attrrow = m_data->m_rowAttrs.GetAttr(row);
2645 wxGridCellAttr *attrcol = m_data->m_colAttrs.GetAttr(col);
2646
2647 if((attrcell != attrrow) && (attrrow != attrcol) && (attrcell != attrcol)){
2648 // Two or more are non NULL
2649 attr = new wxGridCellAttr;
2650 attr->SetKind(wxGridCellAttr::Merged);
2651
2652 //Order important..
2653 if(attrcell){
2654 attr->MergeWith(attrcell);
2655 attrcell->DecRef();
2656 }
2657 if(attrcol){
2658 attr->MergeWith(attrcol);
2659 attrcol->DecRef();
2660 }
2661 if(attrrow){
2662 attr->MergeWith(attrrow);
2663 attrrow->DecRef();
2664 }
2665 //store merge attr if cache implemented
2666 //attr->IncRef();
2667 //m_data->m_mergeAttr.SetAttr(attr, row, col);
2668 }
2669 else
2670 {
2671 // one or none is non null return it or null.
2672 if(attrrow) attr = attrrow;
2673 if(attrcol)
2674 {
2675 if(attr)
2676 attr->DecRef();
2677 attr = attrcol;
2678 }
2679 if(attrcell)
2680 {
2681 if(attr)
2682 attr->DecRef();
2683 attr = attrcell;
2684 }
2685 }
2686 }
2687 break;
2688 case (wxGridCellAttr::Cell):
2689 attr = m_data->m_cellAttrs.GetAttr(row, col);
2690 break;
2691 case (wxGridCellAttr::Col):
2692 attr = m_data->m_colAttrs.GetAttr(col);
2693 break;
2694 case (wxGridCellAttr::Row):
2695 attr = m_data->m_rowAttrs.GetAttr(row);
2696 break;
2697 default:
2698 // unused as yet...
2699 // (wxGridCellAttr::Default):
2700 // (wxGridCellAttr::Merged):
2701 break;
2702 }
2703 }
2704 return attr;
2705}
2706
2707void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
2708 int row, int col)
2709{
2710 if ( !m_data )
2711 InitData();
2712
2713 m_data->m_cellAttrs.SetAttr(attr, row, col);
2714}
2715
2716void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
2717{
2718 if ( !m_data )
2719 InitData();
2720
2721 m_data->m_rowAttrs.SetAttr(attr, row);
2722}
2723
2724void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
2725{
2726 if ( !m_data )
2727 InitData();
2728
2729 m_data->m_colAttrs.SetAttr(attr, col);
2730}
2731
2732void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
2733{
2734 if ( m_data )
2735 {
2736 m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
2737
2738 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
2739 }
2740}
2741
2742void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
2743{
2744 if ( m_data )
2745 {
2746 m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
2747
2748 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
2749 }
2750}
2751
2752// ----------------------------------------------------------------------------
2753// wxGridTypeRegistry
2754// ----------------------------------------------------------------------------
2755
2756wxGridTypeRegistry::~wxGridTypeRegistry()
2757{
2758 size_t count = m_typeinfo.Count();
2759 for ( size_t i = 0; i < count; i++ )
2760 delete m_typeinfo[i];
2761}
2762
2763
2764void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
2765 wxGridCellRenderer* renderer,
2766 wxGridCellEditor* editor)
2767{
2768 wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
2769
2770 // is it already registered?
2771 int loc = FindRegisteredDataType(typeName);
2772 if ( loc != wxNOT_FOUND )
2773 {
2774 delete m_typeinfo[loc];
2775 m_typeinfo[loc] = info;
2776 }
2777 else
2778 {
2779 m_typeinfo.Add(info);
2780 }
2781}
2782
2783int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
2784{
2785 size_t count = m_typeinfo.GetCount();
2786 for ( size_t i = 0; i < count; i++ )
2787 {
2788 if ( typeName == m_typeinfo[i]->m_typeName )
2789 {
2790 return i;
2791 }
2792 }
2793
2794 return wxNOT_FOUND;
2795}
2796
2797int wxGridTypeRegistry::FindDataType(const wxString& typeName)
2798{
2799 int index = FindRegisteredDataType(typeName);
2800 if ( index == wxNOT_FOUND )
2801 {
2802 // check whether this is one of the standard ones, in which case
2803 // register it "on the fly"
2804#if wxUSE_TEXTCTRL
2805 if ( typeName == wxGRID_VALUE_STRING )
2806 {
2807 RegisterDataType(wxGRID_VALUE_STRING,
2808 new wxGridCellStringRenderer,
2809 new wxGridCellTextEditor);
2810 } else
2811#endif // wxUSE_TEXTCTRL
2812#if wxUSE_CHECKBOX
2813 if ( typeName == wxGRID_VALUE_BOOL )
2814 {
2815 RegisterDataType(wxGRID_VALUE_BOOL,
2816 new wxGridCellBoolRenderer,
2817 new wxGridCellBoolEditor);
2818 } else
2819#endif // wxUSE_CHECKBOX
2820#if wxUSE_TEXTCTRL
2821 if ( typeName == wxGRID_VALUE_NUMBER )
2822 {
2823 RegisterDataType(wxGRID_VALUE_NUMBER,
2824 new wxGridCellNumberRenderer,
2825 new wxGridCellNumberEditor);
2826 }
2827 else if ( typeName == wxGRID_VALUE_FLOAT )
2828 {
2829 RegisterDataType(wxGRID_VALUE_FLOAT,
2830 new wxGridCellFloatRenderer,
2831 new wxGridCellFloatEditor);
2832 } else
2833#endif // wxUSE_TEXTCTRL
2834#if wxUSE_COMBOBOX
2835 if ( typeName == wxGRID_VALUE_CHOICE )
2836 {
2837 RegisterDataType(wxGRID_VALUE_CHOICE,
2838 new wxGridCellStringRenderer,
2839 new wxGridCellChoiceEditor);
2840 } else
2841#endif // wxUSE_COMBOBOX
2842 {
2843 return wxNOT_FOUND;
2844 }
2845
2846 // we get here only if just added the entry for this type, so return
2847 // the last index
2848 index = m_typeinfo.GetCount() - 1;
2849 }
2850
2851 return index;
2852}
2853
2854int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
2855{
2856 int index = FindDataType(typeName);
2857 if ( index == wxNOT_FOUND )
2858 {
2859 // the first part of the typename is the "real" type, anything after ':'
2860 // are the parameters for the renderer
2861 index = FindDataType(typeName.BeforeFirst(_T(':')));
2862 if ( index == wxNOT_FOUND )
2863 {
2864 return wxNOT_FOUND;
2865 }
2866
2867 wxGridCellRenderer *renderer = GetRenderer(index);
2868 wxGridCellRenderer *rendererOld = renderer;
2869 renderer = renderer->Clone();
2870 rendererOld->DecRef();
2871
2872 wxGridCellEditor *editor = GetEditor(index);
2873 wxGridCellEditor *editorOld = editor;
2874 editor = editor->Clone();
2875 editorOld->DecRef();
2876
2877 // do it even if there are no parameters to reset them to defaults
2878 wxString params = typeName.AfterFirst(_T(':'));
2879 renderer->SetParameters(params);
2880 editor->SetParameters(params);
2881
2882 // register the new typename
2883 RegisterDataType(typeName, renderer, editor);
2884
2885 // we just registered it, it's the last one
2886 index = m_typeinfo.GetCount() - 1;
2887 }
2888
2889 return index;
2890}
2891
2892wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
2893{
2894 wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
2895 if (renderer)
2896 renderer->IncRef();
2897 return renderer;
2898}
2899
2900wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
2901{
2902 wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
2903 if (editor)
2904 editor->IncRef();
2905 return editor;
2906}
2907
2908// ----------------------------------------------------------------------------
2909// wxGridTableBase
2910// ----------------------------------------------------------------------------
2911
2912IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
2913
2914
2915wxGridTableBase::wxGridTableBase()
2916{
2917 m_view = (wxGrid *) NULL;
2918 m_attrProvider = (wxGridCellAttrProvider *) NULL;
2919}
2920
2921wxGridTableBase::~wxGridTableBase()
2922{
2923 delete m_attrProvider;
2924}
2925
2926void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
2927{
2928 delete m_attrProvider;
2929 m_attrProvider = attrProvider;
2930}
2931
2932bool wxGridTableBase::CanHaveAttributes()
2933{
2934 if ( ! GetAttrProvider() )
2935 {
2936 // use the default attr provider by default
2937 SetAttrProvider(new wxGridCellAttrProvider);
2938 }
2939 return true;
2940}
2941
2942wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind)
2943{
2944 if ( m_attrProvider )
2945 return m_attrProvider->GetAttr(row, col, kind);
2946 else
2947 return (wxGridCellAttr *)NULL;
2948}
2949
2950
2951void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
2952{
2953 if ( m_attrProvider )
2954 {
2955 attr->SetKind(wxGridCellAttr::Cell);
2956 m_attrProvider->SetAttr(attr, row, col);
2957 }
2958 else
2959 {
2960 // as we take ownership of the pointer and don't store it, we must
2961 // free it now
2962 wxSafeDecRef(attr);
2963 }
2964}
2965
2966void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
2967{
2968 if ( m_attrProvider )
2969 {
2970 attr->SetKind(wxGridCellAttr::Row);
2971 m_attrProvider->SetRowAttr(attr, row);
2972 }
2973 else
2974 {
2975 // as we take ownership of the pointer and don't store it, we must
2976 // free it now
2977 wxSafeDecRef(attr);
2978 }
2979}
2980
2981void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
2982{
2983 if ( m_attrProvider )
2984 {
2985 attr->SetKind(wxGridCellAttr::Col);
2986 m_attrProvider->SetColAttr(attr, col);
2987 }
2988 else
2989 {
2990 // as we take ownership of the pointer and don't store it, we must
2991 // free it now
2992 wxSafeDecRef(attr);
2993 }
2994}
2995
2996bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos),
2997 size_t WXUNUSED(numRows) )
2998{
2999 wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
3000
3001 return false;
3002}
3003
3004bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) )
3005{
3006 wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
3007
3008 return false;
3009}
3010
3011bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos),
3012 size_t WXUNUSED(numRows) )
3013{
3014 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
3015
3016 return false;
3017}
3018
3019bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos),
3020 size_t WXUNUSED(numCols) )
3021{
3022 wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
3023
3024 return false;
3025}
3026
3027bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) )
3028{
3029 wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
3030
3031 return false;
3032}
3033
3034bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos),
3035 size_t WXUNUSED(numCols) )
3036{
3037 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
3038
3039 return false;
3040}
3041
3042
3043wxString wxGridTableBase::GetRowLabelValue( int row )
3044{
3045 wxString s;
3046 s << row + 1; // RD: Starting the rows at zero confuses users, no matter
3047 // how much it makes sense to us geeks.
3048 return s;
3049}
3050
3051wxString wxGridTableBase::GetColLabelValue( int col )
3052{
3053 // default col labels are:
3054 // cols 0 to 25 : A-Z
3055 // cols 26 to 675 : AA-ZZ
3056 // etc.
3057
3058 wxString s;
3059 unsigned int i, n;
3060 for ( n = 1; ; n++ )
3061 {
3062 s += (wxChar) (_T('A') + (wxChar)( col%26 ));
3063 col = col/26 - 1;
3064 if ( col < 0 ) break;
3065 }
3066
3067 // reverse the string...
3068 wxString s2;
3069 for ( i = 0; i < n; i++ )
3070 {
3071 s2 += s[n-i-1];
3072 }
3073
3074 return s2;
3075}
3076
3077
3078wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
3079{
3080 return wxGRID_VALUE_STRING;
3081}
3082
3083bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
3084 const wxString& typeName )
3085{
3086 return typeName == wxGRID_VALUE_STRING;
3087}
3088
3089bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
3090{
3091 return CanGetValueAs(row, col, typeName);
3092}
3093
3094long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
3095{
3096 return 0;
3097}
3098
3099double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
3100{
3101 return 0.0;
3102}
3103
3104bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
3105{
3106 return false;
3107}
3108
3109void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
3110 long WXUNUSED(value) )
3111{
3112}
3113
3114void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
3115 double WXUNUSED(value) )
3116{
3117}
3118
3119void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
3120 bool WXUNUSED(value) )
3121{
3122}
3123
3124
3125void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3126 const wxString& WXUNUSED(typeName) )
3127{
3128 return NULL;
3129}
3130
3131void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3132 const wxString& WXUNUSED(typeName),
3133 void* WXUNUSED(value) )
3134{
3135}
3136
3137//////////////////////////////////////////////////////////////////////
3138//
3139// Message class for the grid table to send requests and notifications
3140// to the grid view
3141//
3142
3143wxGridTableMessage::wxGridTableMessage()
3144{
3145 m_table = (wxGridTableBase *) NULL;
3146 m_id = -1;
3147 m_comInt1 = -1;
3148 m_comInt2 = -1;
3149}
3150
3151wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
3152 int commandInt1, int commandInt2 )
3153{
3154 m_table = table;
3155 m_id = id;
3156 m_comInt1 = commandInt1;
3157 m_comInt2 = commandInt2;
3158}
3159
3160
3161
3162//////////////////////////////////////////////////////////////////////
3163//
3164// A basic grid table for string data. An object of this class will
3165// created by wxGrid if you don't specify an alternative table class.
3166//
3167
3168WX_DEFINE_OBJARRAY(wxGridStringArray)
3169
3170IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
3171
3172wxGridStringTable::wxGridStringTable()
3173 : wxGridTableBase()
3174{
3175}
3176
3177wxGridStringTable::wxGridStringTable( int numRows, int numCols )
3178 : wxGridTableBase()
3179{
3180 m_data.Alloc( numRows );
3181
3182 wxArrayString sa;
3183 sa.Alloc( numCols );
3184 sa.Add( wxEmptyString, numCols );
3185
3186 m_data.Add( sa, numRows );
3187}
3188
3189wxGridStringTable::~wxGridStringTable()
3190{
3191}
3192
3193int wxGridStringTable::GetNumberRows()
3194{
3195 return m_data.GetCount();
3196}
3197
3198int wxGridStringTable::GetNumberCols()
3199{
3200 if ( m_data.GetCount() > 0 )
3201 return m_data[0].GetCount();
3202 else
3203 return 0;
3204}
3205
3206wxString wxGridStringTable::GetValue( int row, int col )
3207{
3208 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3209 wxEmptyString,
3210 _T("invalid row or column index in wxGridStringTable") );
3211
3212 return m_data[row][col];
3213}
3214
3215void wxGridStringTable::SetValue( int row, int col, const wxString& value )
3216{
3217 wxCHECK_RET( (row < GetNumberRows()) && (col < GetNumberCols()),
3218 _T("invalid row or column index in wxGridStringTable") );
3219
3220 m_data[row][col] = value;
3221}
3222
3223bool wxGridStringTable::IsEmptyCell( int row, int col )
3224{
3225 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3226 true,
3227 _T("invalid row or column index in wxGridStringTable") );
3228
3229 return (m_data[row][col] == wxEmptyString);
3230}
3231
3232void wxGridStringTable::Clear()
3233{
3234 int row, col;
3235 int numRows, numCols;
3236
3237 numRows = m_data.GetCount();
3238 if ( numRows > 0 )
3239 {
3240 numCols = m_data[0].GetCount();
3241
3242 for ( row = 0; row < numRows; row++ )
3243 {
3244 for ( col = 0; col < numCols; col++ )
3245 {
3246 m_data[row][col] = wxEmptyString;
3247 }
3248 }
3249 }
3250}
3251
3252
3253bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
3254{
3255 size_t curNumRows = m_data.GetCount();
3256 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3257 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3258
3259 if ( pos >= curNumRows )
3260 {
3261 return AppendRows( numRows );
3262 }
3263
3264 wxArrayString sa;
3265 sa.Alloc( curNumCols );
3266 sa.Add( wxEmptyString, curNumCols );
3267 m_data.Insert( sa, pos, numRows );
3268 if ( GetView() )
3269 {
3270 wxGridTableMessage msg( this,
3271 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
3272 pos,
3273 numRows );
3274
3275 GetView()->ProcessTableMessage( msg );
3276 }
3277
3278 return true;
3279}
3280
3281bool wxGridStringTable::AppendRows( size_t numRows )
3282{
3283 size_t curNumRows = m_data.GetCount();
3284 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3285 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3286
3287 wxArrayString sa;
3288 if ( curNumCols > 0 )
3289 {
3290 sa.Alloc( curNumCols );
3291 sa.Add( wxEmptyString, curNumCols );
3292 }
3293
3294 m_data.Add( sa, numRows );
3295
3296 if ( GetView() )
3297 {
3298 wxGridTableMessage msg( this,
3299 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
3300 numRows );
3301
3302 GetView()->ProcessTableMessage( msg );
3303 }
3304
3305 return true;
3306}
3307
3308bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
3309{
3310 size_t curNumRows = m_data.GetCount();
3311
3312 if ( pos >= curNumRows )
3313 {
3314 wxFAIL_MSG( wxString::Format
3315 (
3316 wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"),
3317 (unsigned long)pos,
3318 (unsigned long)numRows,
3319 (unsigned long)curNumRows
3320 ) );
3321
3322 return false;
3323 }
3324
3325 if ( numRows > curNumRows - pos )
3326 {
3327 numRows = curNumRows - pos;
3328 }
3329
3330 if ( numRows >= curNumRows )
3331 {
3332 m_data.Clear();
3333 }
3334 else
3335 {
3336 m_data.RemoveAt( pos, numRows );
3337 }
3338 if ( GetView() )
3339 {
3340 wxGridTableMessage msg( this,
3341 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
3342 pos,
3343 numRows );
3344
3345 GetView()->ProcessTableMessage( msg );
3346 }
3347
3348 return true;
3349}
3350
3351bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
3352{
3353 size_t row, col;
3354
3355 size_t curNumRows = m_data.GetCount();
3356 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3357 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3358
3359 if ( pos >= curNumCols )
3360 {
3361 return AppendCols( numCols );
3362 }
3363
3364 for ( row = 0; row < curNumRows; row++ )
3365 {
3366 for ( col = pos; col < pos + numCols; col++ )
3367 {
3368 m_data[row].Insert( wxEmptyString, col );
3369 }
3370 }
3371 if ( GetView() )
3372 {
3373 wxGridTableMessage msg( this,
3374 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
3375 pos,
3376 numCols );
3377
3378 GetView()->ProcessTableMessage( msg );
3379 }
3380
3381 return true;
3382}
3383
3384bool wxGridStringTable::AppendCols( size_t numCols )
3385{
3386 size_t row;
3387
3388 size_t curNumRows = m_data.GetCount();
3389#if 0
3390 if ( !curNumRows )
3391 {
3392 // TODO: something better than this ?
3393 //
3394 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") );
3395 return false;
3396 }
3397#endif
3398
3399 for ( row = 0; row < curNumRows; row++ )
3400 {
3401 m_data[row].Add( wxEmptyString, numCols );
3402 }
3403
3404 if ( GetView() )
3405 {
3406 wxGridTableMessage msg( this,
3407 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
3408 numCols );
3409
3410 GetView()->ProcessTableMessage( msg );
3411 }
3412
3413 return true;
3414}
3415
3416bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
3417{
3418 size_t row;
3419
3420 size_t curNumRows = m_data.GetCount();
3421 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3422 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3423
3424 if ( pos >= curNumCols )
3425 {
3426 wxFAIL_MSG( wxString::Format
3427 (
3428 wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"),
3429 (unsigned long)pos,
3430 (unsigned long)numCols,
3431 (unsigned long)curNumCols
3432 ) );
3433 return false;
3434 }
3435
3436 if ( numCols > curNumCols - pos )
3437 {
3438 numCols = curNumCols - pos;
3439 }
3440
3441 for ( row = 0; row < curNumRows; row++ )
3442 {
3443 if ( numCols >= curNumCols )
3444 {
3445 m_data[row].Clear();
3446 }
3447 else
3448 {
3449 m_data[row].RemoveAt( pos, numCols );
3450 }
3451 }
3452 if ( GetView() )
3453 {
3454 wxGridTableMessage msg( this,
3455 wxGRIDTABLE_NOTIFY_COLS_DELETED,
3456 pos,
3457 numCols );
3458
3459 GetView()->ProcessTableMessage( msg );
3460 }
3461
3462 return true;
3463}
3464
3465wxString wxGridStringTable::GetRowLabelValue( int row )
3466{
3467 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3468 {
3469 // using default label
3470 //
3471 return wxGridTableBase::GetRowLabelValue( row );
3472 }
3473 else
3474 {
3475 return m_rowLabels[ row ];
3476 }
3477}
3478
3479wxString wxGridStringTable::GetColLabelValue( int col )
3480{
3481 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3482 {
3483 // using default label
3484 //
3485 return wxGridTableBase::GetColLabelValue( col );
3486 }
3487 else
3488 {
3489 return m_colLabels[ col ];
3490 }
3491}
3492
3493void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
3494{
3495 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3496 {
3497 int n = m_rowLabels.GetCount();
3498 int i;
3499 for ( i = n; i <= row; i++ )
3500 {
3501 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
3502 }
3503 }
3504
3505 m_rowLabels[row] = value;
3506}
3507
3508void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
3509{
3510 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3511 {
3512 int n = m_colLabels.GetCount();
3513 int i;
3514 for ( i = n; i <= col; i++ )
3515 {
3516 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
3517 }
3518 }
3519
3520 m_colLabels[col] = value;
3521}
3522
3523
3524
3525//////////////////////////////////////////////////////////////////////
3526//////////////////////////////////////////////////////////////////////
3527
3528IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
3529
3530BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
3531 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
3532 EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel)
3533 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
3534 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
3535 EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp )
3536 EVT_CHAR ( wxGridRowLabelWindow::OnChar )
3537END_EVENT_TABLE()
3538
3539wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
3540 wxWindowID id,
3541 const wxPoint &pos, const wxSize &size )
3542 : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
3543{
3544 m_owner = parent;
3545}
3546
3547void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3548{
3549 wxPaintDC dc(this);
3550
3551 // NO - don't do this because it will set both the x and y origin
3552 // coords to match the parent scrolled window and we just want to
3553 // set the y coord - MB
3554 //
3555 // m_owner->PrepareDC( dc );
3556
3557 int x, y;
3558 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3559 dc.SetDeviceOrigin( 0, -y );
3560
3561 wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
3562 m_owner->DrawRowLabels( dc , rows );
3563}
3564
3565
3566void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
3567{
3568 m_owner->ProcessRowLabelMouseEvent( event );
3569}
3570
3571
3572void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event )
3573{
3574 m_owner->GetEventHandler()->ProcessEvent(event);
3575}
3576
3577
3578// This seems to be required for wxMotif otherwise the mouse
3579// cursor must be in the cell edit control to get key events
3580//
3581void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
3582{
3583 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3584}
3585
3586void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event )
3587{
3588 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3589}
3590
3591void wxGridRowLabelWindow::OnChar( wxKeyEvent& event )
3592{
3593 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3594}
3595
3596
3597
3598//////////////////////////////////////////////////////////////////////
3599
3600IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
3601
3602BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
3603 EVT_PAINT( wxGridColLabelWindow::OnPaint )
3604 EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel)
3605 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
3606 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
3607 EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp )
3608 EVT_CHAR ( wxGridColLabelWindow::OnChar )
3609END_EVENT_TABLE()
3610
3611wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
3612 wxWindowID id,
3613 const wxPoint &pos, const wxSize &size )
3614 : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
3615{
3616 m_owner = parent;
3617}
3618
3619void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3620{
3621 wxPaintDC dc(this);
3622
3623 // NO - don't do this because it will set both the x and y origin
3624 // coords to match the parent scrolled window and we just want to
3625 // set the x coord - MB
3626 //
3627 // m_owner->PrepareDC( dc );
3628
3629 int x, y;
3630 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3631 dc.SetDeviceOrigin( -x, 0 );
3632
3633 wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() );
3634 m_owner->DrawColLabels( dc , cols );
3635}
3636
3637
3638void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
3639{
3640 m_owner->ProcessColLabelMouseEvent( event );
3641}
3642
3643void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event )
3644{
3645 m_owner->GetEventHandler()->ProcessEvent(event);
3646}
3647
3648
3649// This seems to be required for wxMotif otherwise the mouse
3650// cursor must be in the cell edit control to get key events
3651//
3652void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
3653{
3654 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3655}
3656
3657void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event )
3658{
3659 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3660}
3661
3662void wxGridColLabelWindow::OnChar( wxKeyEvent& event )
3663{
3664 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3665}
3666
3667
3668//////////////////////////////////////////////////////////////////////
3669
3670IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
3671
3672BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
3673 EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel)
3674 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
3675 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
3676 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
3677 EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp )
3678 EVT_CHAR ( wxGridCornerLabelWindow::OnChar )
3679END_EVENT_TABLE()
3680
3681wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
3682 wxWindowID id,
3683 const wxPoint &pos, const wxSize &size )
3684 : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
3685{
3686 m_owner = parent;
3687}
3688
3689void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3690{
3691 wxPaintDC dc(this);
3692
3693 int client_height = 0;
3694 int client_width = 0;
3695 GetClientSize( &client_width, &client_height );
3696
3697#if __WXGTK__
3698 wxRect rect;
3699 rect.SetX( 1 );
3700 rect.SetY( 1 );
3701 rect.SetWidth( client_width - 2 );
3702 rect.SetHeight( client_height - 2 );
3703
3704 wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 );
3705#else
3706 dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW),1, wxSOLID) );
3707 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
3708 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
3709 dc.DrawLine( 0, 0, client_width, 0 );
3710 dc.DrawLine( 0, 0, 0, client_height );
3711
3712 dc.SetPen( *wxWHITE_PEN );
3713 dc.DrawLine( 1, 1, client_width-1, 1 );
3714 dc.DrawLine( 1, 1, 1, client_height-1 );
3715#endif
3716}
3717
3718
3719void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
3720{
3721 m_owner->ProcessCornerLabelMouseEvent( event );
3722}
3723
3724
3725void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event )
3726{
3727 m_owner->GetEventHandler()->ProcessEvent(event);
3728}
3729
3730// This seems to be required for wxMotif otherwise the mouse
3731// cursor must be in the cell edit control to get key events
3732//
3733void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
3734{
3735 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3736}
3737
3738void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event )
3739{
3740 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3741}
3742
3743void wxGridCornerLabelWindow::OnChar( wxKeyEvent& event )
3744{
3745 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3746}
3747
3748
3749//////////////////////////////////////////////////////////////////////
3750
3751IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow )
3752
3753BEGIN_EVENT_TABLE( wxGridWindow, wxWindow )
3754 EVT_PAINT( wxGridWindow::OnPaint )
3755 EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel)
3756 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
3757 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
3758 EVT_KEY_UP( wxGridWindow::OnKeyUp )
3759 EVT_CHAR ( wxGridWindow::OnChar )
3760 EVT_SET_FOCUS( wxGridWindow::OnFocus )
3761 EVT_KILL_FOCUS( wxGridWindow::OnFocus )
3762 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
3763END_EVENT_TABLE()
3764
3765wxGridWindow::wxGridWindow( wxGrid *parent,
3766 wxGridRowLabelWindow *rowLblWin,
3767 wxGridColLabelWindow *colLblWin,
3768 wxWindowID id,
3769 const wxPoint &pos,
3770 const wxSize &size )
3771 : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxCLIP_CHILDREN|wxFULL_REPAINT_ON_RESIZE,
3772 wxT("grid window") )
3773
3774{
3775 m_owner = parent;
3776 m_rowLabelWin = rowLblWin;
3777 m_colLabelWin = colLblWin;
3778}
3779
3780
3781void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
3782{
3783 wxPaintDC dc( this );
3784 m_owner->PrepareDC( dc );
3785 wxRegion reg = GetUpdateRegion();
3786 wxGridCellCoordsArray DirtyCells = m_owner->CalcCellsExposed( reg );
3787 m_owner->DrawGridCellArea( dc , DirtyCells);
3788#if WXGRID_DRAW_LINES
3789 m_owner->DrawAllGridLines( dc, reg );
3790#endif
3791 m_owner->DrawGridSpace( dc );
3792 m_owner->DrawHighlight( dc , DirtyCells );
3793}
3794
3795
3796void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
3797{
3798 wxWindow::ScrollWindow( dx, dy, rect );
3799 m_rowLabelWin->ScrollWindow( 0, dy, rect );
3800 m_colLabelWin->ScrollWindow( dx, 0, rect );
3801}
3802
3803
3804void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
3805{
3806 if (event.ButtonDown(wxMOUSE_BTN_LEFT) && FindFocus() != this)
3807 SetFocus();
3808
3809 m_owner->ProcessGridCellMouseEvent( event );
3810}
3811
3812void wxGridWindow::OnMouseWheel( wxMouseEvent& event )
3813{
3814 m_owner->GetEventHandler()->ProcessEvent(event);
3815}
3816
3817// This seems to be required for wxMotif/wxGTK otherwise the mouse
3818// cursor must be in the cell edit control to get key events
3819//
3820void wxGridWindow::OnKeyDown( wxKeyEvent& event )
3821{
3822 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3823}
3824
3825void wxGridWindow::OnKeyUp( wxKeyEvent& event )
3826{
3827 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3828}
3829
3830void wxGridWindow::OnChar( wxKeyEvent& event )
3831{
3832 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3833}
3834
3835void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
3836{
3837}
3838
3839void wxGridWindow::OnFocus(wxFocusEvent& event)
3840{
3841 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3842 event.Skip();
3843}
3844
3845//////////////////////////////////////////////////////////////////////
3846
3847// Internal Helper function for computing row or column from some
3848// (unscrolled) coordinate value, using either
3849// m_defaultRowHeight/m_defaultColWidth or binary search on array
3850// of m_rowBottoms/m_ColRights to speed up the search!
3851
3852// Internal helper macros for simpler use of that function
3853
3854static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
3855 const wxArrayInt& BorderArray, int nMax,
3856 bool clipToMinMax);
3857
3858#define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \
3859 m_minAcceptableColWidth, \
3860 m_colRights, m_numCols, true)
3861#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \
3862 m_minAcceptableRowHeight, \
3863 m_rowBottoms, m_numRows, true)
3864/////////////////////////////////////////////////////////////////////
3865
3866#if wxUSE_EXTENDED_RTTI
3867WX_DEFINE_FLAGS( wxGridStyle )
3868
3869wxBEGIN_FLAGS( wxGridStyle )
3870 // new style border flags, we put them first to
3871 // use them for streaming out
3872 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
3873 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
3874 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
3875 wxFLAGS_MEMBER(wxBORDER_RAISED)
3876 wxFLAGS_MEMBER(wxBORDER_STATIC)
3877 wxFLAGS_MEMBER(wxBORDER_NONE)
3878
3879 // old style border flags
3880 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
3881 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
3882 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
3883 wxFLAGS_MEMBER(wxRAISED_BORDER)
3884 wxFLAGS_MEMBER(wxSTATIC_BORDER)
3885 wxFLAGS_MEMBER(wxBORDER)
3886
3887 // standard window styles
3888 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
3889 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
3890 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
3891 wxFLAGS_MEMBER(wxWANTS_CHARS)
3892 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3893 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
3894 wxFLAGS_MEMBER(wxVSCROLL)
3895 wxFLAGS_MEMBER(wxHSCROLL)
3896
3897wxEND_FLAGS( wxGridStyle )
3898
3899IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid, wxScrolledWindow,"wx/grid.h")
3900
3901wxBEGIN_PROPERTIES_TABLE(wxGrid)
3902 wxHIDE_PROPERTY( Children )
3903 wxPROPERTY_FLAGS( WindowStyle , wxGridStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3904wxEND_PROPERTIES_TABLE()
3905
3906wxBEGIN_HANDLERS_TABLE(wxGrid)
3907wxEND_HANDLERS_TABLE()
3908
3909wxCONSTRUCTOR_5( wxGrid , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
3910
3911/*
3912