1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        griddemo.cpp
3 // Purpose:     Grid control wxWidgets sample
4 // Author:      Michael Bedward
5 // Modified by: Santiago Palacios
6 // Copyright:   (c) Michael Bedward, Julian Smart, Vadim Zeitlin
7 // Licence:     wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 // ============================================================================
11 // declarations
12 // ============================================================================
13 
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17 
18 // For compilers that support precompilation, includes "wx/wx.h".
19 #include "wx/wxprec.h"
20 
21 
22 #ifndef WX_PRECOMP
23     #include "wx/wx.h"
24 #endif
25 
26 #include "wx/colordlg.h"
27 #include "wx/fontdlg.h"
28 #include "wx/numdlg.h"
29 #include "wx/aboutdlg.h"
30 
31 #include "wx/grid.h"
32 #include "wx/headerctrl.h"
33 #include "wx/generic/gridctrl.h"
34 #include "wx/generic/grideditors.h"
35 
36 #include "griddemo.h"
37 
38 #ifndef wxHAS_IMAGES_IN_RESOURCES
39     #include "../sample.xpm"
40 #endif
41 
42 // Custom renderer that renders column header cells without borders and in
43 // italic
44 class CustomColumnHeaderRenderer : public wxGridColumnHeaderRenderer
45 {
46 public:
CustomColumnHeaderRenderer(const wxColour & colFg,const wxColour & colBg)47     CustomColumnHeaderRenderer(const wxColour& colFg, const wxColour& colBg)
48         : m_colFg(colFg),
49           m_colBg(colBg)
50     {
51     }
52 
DrawLabel(const wxGrid & WXUNUSED (grid),wxDC & dc,const wxString & value,const wxRect & rect,int horizAlign,int vertAlign,int WXUNUSED (textOrientation)) const53     virtual void DrawLabel(const wxGrid& WXUNUSED(grid),
54                            wxDC& dc,
55                            const wxString& value,
56                            const wxRect& rect,
57                            int horizAlign,
58                            int vertAlign,
59                            int WXUNUSED(textOrientation)) const wxOVERRIDE
60     {
61         dc.SetTextForeground(m_colFg);
62         dc.SetFont(wxITALIC_FONT->Bold());
63         dc.DrawLabel(value, rect, horizAlign | vertAlign);
64     }
65 
DrawBorder(const wxGrid & WXUNUSED (grid),wxDC & dc,wxRect & rect) const66     virtual void DrawBorder(const wxGrid& WXUNUSED(grid),
67                             wxDC& dc,
68                             wxRect& rect) const wxOVERRIDE
69     {
70         dc.SetPen(*wxTRANSPARENT_PEN);
71         dc.SetBrush(wxBrush(m_colBg));
72         dc.DrawRectangle(rect);
73     }
74 
75 private:
76     const wxColour m_colFg, m_colBg;
77 
78     wxDECLARE_NO_COPY_CLASS(CustomColumnHeaderRenderer);
79 };
80 
81 // And a custom attributes provider which uses custom column header renderer
82 // defined above
83 class CustomColumnHeadersProvider : public wxGridCellAttrProvider
84 {
85 public:
86     // by default custom column renderer is not used, call
87     // UseCustomColHeaders() to enable it
CustomColumnHeadersProvider()88     CustomColumnHeadersProvider()
89         : m_customOddRenderer(*wxYELLOW, *wxBLUE),
90           m_customEvenRenderer(*wxWHITE, *wxBLACK),
91           m_useCustom(false)
92     {
93     }
94 
95     // enable or disable the use of custom renderer for column headers
UseCustomColHeaders(bool use=true)96     void UseCustomColHeaders(bool use = true) { m_useCustom = use; }
97 
98 protected:
GetColumnHeaderRenderer(int col)99     virtual const wxGridColumnHeaderRenderer& GetColumnHeaderRenderer(int col) wxOVERRIDE
100     {
101         // if enabled, use custom renderers
102         if ( m_useCustom )
103         {
104             // and use different ones for odd and even columns -- just to show
105             // that we can
106             return col % 2 ? m_customOddRenderer : m_customEvenRenderer;
107         }
108 
109         return wxGridCellAttrProvider::GetColumnHeaderRenderer(col);
110     }
111 
112 private:
113     CustomColumnHeaderRenderer m_customOddRenderer,
114                                m_customEvenRenderer;
115 
116     bool m_useCustom;
117 
118     wxDECLARE_NO_COPY_CLASS(CustomColumnHeadersProvider);
119 };
120 
121 // ----------------------------------------------------------------------------
122 // Custom wxGrid renderer and editor for showing stars as used for rating
123 // ----------------------------------------------------------------------------
124 
125 // Max number of stars shown by MyGridStarRenderer.
126 static const int MAX_STARS = 5;
127 
128 // Helper function returning the number between 0 and MAX_STARS corresponding
129 // to the value of the cell.
GetStarValue(wxGrid & grid,int row,int col)130 static int GetStarValue(wxGrid& grid, int row, int col)
131 {
132     unsigned long n = 0;
133     if ( !grid.GetCellValue(row, col).ToULong(&n) || n > MAX_STARS )
134         n = 0;
135 
136     return static_cast<int>(n);
137 }
138 
139 // Another helper returning the string containing the appropriate number of
140 // black and white stars.
GetStarString(int numBlackStars)141 static wxString GetStarString(int numBlackStars)
142 {
143     const wxUniChar BLACK_STAR = 0x2605;
144     const wxUniChar WHITE_STAR = 0x2606;
145 
146     return wxString(BLACK_STAR, numBlackStars) +
147             wxString(WHITE_STAR, MAX_STARS - numBlackStars);
148 }
149 
150 // Renders the value of the cell, which is supposed to be a number between 1
151 // and 5, as a sequence of that number of black stars followed by the number of
152 // white stars needed to have 5 stars in total.
153 class MyGridStarRenderer : public wxGridCellRenderer
154 {
155 public:
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rect,int row,int col,bool isSelected)156     virtual void Draw(wxGrid& grid,
157                       wxGridCellAttr& attr,
158                       wxDC& dc,
159                       const wxRect& rect,
160                       int row, int col,
161                       bool isSelected) wxOVERRIDE
162     {
163         wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
164 
165         SetTextColoursAndFont(grid, attr, dc, isSelected);
166 
167         grid.DrawTextRectangle(dc, GetStarString(GetStarValue(grid, row, col)),
168                                rect, attr);
169     }
170 
GetBestSize(wxGrid & WXUNUSED (grid),wxGridCellAttr & attr,wxDC & dc,int WXUNUSED (row),int WXUNUSED (col))171     virtual wxSize GetBestSize(wxGrid& WXUNUSED(grid),
172                                wxGridCellAttr& attr,
173                                wxDC& dc,
174                                int WXUNUSED(row),
175                                int WXUNUSED(col)) wxOVERRIDE
176     {
177         dc.SetFont(attr.GetFont());
178         return dc.GetTextExtent(GetStarString(MAX_STARS));
179     }
180 
Clone() const181     virtual wxGridCellRenderer *Clone() const wxOVERRIDE
182     {
183         return new MyGridStarRenderer();
184     }
185 };
186 
187 // Activatable editor cycling the number of stars on each activation.
188 class MyGridStarEditor : public wxGridCellActivatableEditor
189 {
190 public:
191     virtual wxGridActivationResult
TryActivate(int row,int col,wxGrid * grid,const wxGridActivationSource & actSource)192     TryActivate(int row, int col, wxGrid* grid,
193                 const wxGridActivationSource& actSource) wxOVERRIDE
194     {
195         int numStars = -1;
196 
197         switch ( actSource.GetOrigin() )
198         {
199             case wxGridActivationSource::Program:
200                 // It isn't really possible to programmatically start editing a
201                 // cell using this editor.
202                 return wxGridActivationResult::DoNothing();
203 
204             case wxGridActivationSource::Key:
205                 switch ( actSource.GetKeyEvent().GetKeyCode() )
206                 {
207                     case '0': numStars = 0; break;
208                     case '1': numStars = 1; break;
209                     case '2': numStars = 2; break;
210                     case '3': numStars = 3; break;
211                     case '4': numStars = 4; break;
212                     case '5': numStars = 5; break;
213                     case ' ':
214                         // Use space key to cycle over the values.
215                         break;
216 
217                     default:
218                         return wxGridActivationResult::DoNothing();
219                 }
220 
221                 break;
222 
223             case wxGridActivationSource::Mouse:
224                 // Ideally we should use the mouse event position to determine
225                 // on which star the user clicked, but for now keep it simple
226                 // and just cycle through the star value.
227                 break;
228         }
229 
230         if ( numStars == -1 )
231             numStars = (GetStarValue(*grid, row, col) + 1) % (MAX_STARS + 1);
232 
233         m_value.Printf("%d", numStars);
234 
235         return wxGridActivationResult::DoChange(m_value);
236     }
237 
DoActivate(int row,int col,wxGrid * grid)238     virtual void DoActivate(int row, int col, wxGrid* grid) wxOVERRIDE
239     {
240         grid->SetCellValue(row, col, m_value);
241     }
242 
Clone() const243     virtual wxGridCellEditor *Clone() const wxOVERRIDE
244     {
245         return new MyGridStarEditor();
246     }
247 
248 private:
249     wxString m_value;
250 };
251 
252 // ----------------------------------------------------------------------------
253 // wxWin macros
254 // ----------------------------------------------------------------------------
255 
256 wxIMPLEMENT_APP(GridApp);
257 
258 // ============================================================================
259 // implementation
260 // ============================================================================
261 
262 // ----------------------------------------------------------------------------
263 // GridApp
264 // ----------------------------------------------------------------------------
265 
OnInit()266 bool GridApp::OnInit()
267 {
268     GridFrame *frame = new GridFrame;
269     frame->Show(true);
270 
271     return true;
272 }
273 
274 // ----------------------------------------------------------------------------
275 // GridFrame
276 // ----------------------------------------------------------------------------
277 
wxBEGIN_EVENT_TABLE(GridFrame,wxFrame)278 wxBEGIN_EVENT_TABLE( GridFrame, wxFrame )
279     EVT_MENU( ID_TOGGLEROWLABELS,  GridFrame::ToggleRowLabels )
280     EVT_MENU( ID_TOGGLECOLLABELS,  GridFrame::ToggleColLabels )
281     EVT_MENU( ID_TOGGLEEDIT, GridFrame::ToggleEditing )
282     EVT_MENU( ID_TOGGLEROWSIZING, GridFrame::ToggleRowSizing )
283     EVT_MENU( ID_TOGGLECOLSIZING, GridFrame::ToggleColSizing )
284     EVT_MENU( ID_TOGGLECOLMOVING, GridFrame::ToggleColMoving )
285     EVT_MENU( ID_TOGGLECOLHIDING, GridFrame::ToggleColHiding )
286     EVT_MENU( ID_TOGGLEGRIDSIZING, GridFrame::ToggleGridSizing )
287     EVT_MENU( ID_TOGGLEGRIDDRAGCELL, GridFrame::ToggleGridDragCell )
288     EVT_MENU( ID_COLNATIVEHEADER, GridFrame::SetNativeColHeader )
289     EVT_MENU( ID_COLNATIVELABELS, GridFrame::SetNativeColLabels )
290     EVT_MENU( ID_COLDEFAULTHEADER, GridFrame::SetDefaultColHeader )
291     EVT_MENU( ID_COLCUSTOMHEADER, GridFrame::SetCustomColHeader )
292     EVT_MENU_RANGE( ID_TAB_STOP, ID_TAB_LEAVE, GridFrame::SetTabBehaviour )
293     EVT_MENU( ID_TAB_CUSTOM, GridFrame::SetTabCustomHandler )
294     EVT_MENU( ID_TOGGLEGRIDLINES, GridFrame::ToggleGridLines )
295     EVT_MENU( ID_AUTOSIZECOLS, GridFrame::AutoSizeCols )
296     EVT_MENU( ID_CELLOVERFLOW, GridFrame::CellOverflow )
297     EVT_MENU( ID_RESIZECELL, GridFrame::ResizeCell )
298     EVT_MENU( ID_TOGGLE_CHECKERED_CELLS, GridFrame::ToggleCheckeredCells )
299     EVT_MENU( ID_TOGGLE_COLOURED_CELLS, GridFrame::ToggleColouredCells )
300     EVT_MENU( ID_SETLABELCOLOUR, GridFrame::SetLabelColour )
301     EVT_MENU( ID_SETLABELTEXTCOLOUR, GridFrame::SetLabelTextColour )
302     EVT_MENU( ID_SETLABEL_FONT, GridFrame::SetLabelFont )
303     EVT_MENU( ID_ROWLABELHORIZALIGN, GridFrame::SetRowLabelHorizAlignment )
304     EVT_MENU( ID_ROWLABELVERTALIGN, GridFrame::SetRowLabelVertAlignment )
305     EVT_MENU( ID_COLLABELHORIZALIGN, GridFrame::SetColLabelHorizAlignment )
306     EVT_MENU( ID_COLLABELVERTALIGN, GridFrame::SetColLabelVertAlignment )
307     EVT_MENU( ID_CORNERLABELHORIZALIGN, GridFrame::SetCornerLabelHorizAlignment )
308     EVT_MENU( ID_CORNERLABELVERTALIGN, GridFrame::SetCornerLabelVertAlignment )
309     EVT_MENU( ID_CORNERLABELORIENTATION, GridFrame::ToggleCornerLabelOrientation )
310     EVT_MENU( ID_GRIDLINECOLOUR, GridFrame::SetGridLineColour )
311     EVT_MENU( ID_INSERTROW, GridFrame::InsertRow )
312     EVT_MENU( ID_INSERTCOL, GridFrame::InsertCol )
313     EVT_MENU( ID_DELETEROW, GridFrame::DeleteSelectedRows )
314     EVT_MENU( ID_DELETECOL, GridFrame::DeleteSelectedCols )
315     EVT_MENU( ID_CLEARGRID, GridFrame::ClearGrid )
316     EVT_MENU( ID_EDITCELL, GridFrame::EditCell )
317     EVT_MENU( ID_SETCORNERLABEL, GridFrame::SetCornerLabelValue )
318     EVT_MENU( ID_SHOWSEL,   GridFrame::ShowSelection )
319     EVT_MENU( ID_SELCELLS,  GridFrame::SelectCells )
320     EVT_MENU( ID_SELROWS,  GridFrame::SelectRows )
321     EVT_MENU( ID_SELCOLS,  GridFrame::SelectCols )
322     EVT_MENU( ID_SELROWSORCOLS,  GridFrame::SelectRowsOrCols )
323     EVT_MENU( ID_SELNONE,  GridFrame::SelectNone )
324 
325     EVT_MENU( ID_FREEZE_OR_THAW,  GridFrame::FreezeOrThaw )
326 
327     EVT_MENU( ID_SET_CELL_FG_COLOUR, GridFrame::SetCellFgColour )
328     EVT_MENU( ID_SET_CELL_BG_COLOUR, GridFrame::SetCellBgColour )
329 
330     EVT_MENU( wxID_ABOUT, GridFrame::OnAbout )
331     EVT_MENU( wxID_CLEAR, GridFrame::OnClear )
332     EVT_MENU( wxID_EXIT, GridFrame::OnQuit )
333     EVT_MENU( ID_VTABLE, GridFrame::OnVTable)
334     EVT_MENU( ID_BUGS_TABLE, GridFrame::OnBugsTable)
335     EVT_MENU( ID_TABULAR_TABLE, GridFrame::OnTabularTable)
336 
337     EVT_MENU( ID_DESELECT_CELL, GridFrame::DeselectCell)
338     EVT_MENU( ID_DESELECT_COL, GridFrame::DeselectCol)
339     EVT_MENU( ID_DESELECT_ROW, GridFrame::DeselectRow)
340     EVT_MENU( ID_DESELECT_ALL, GridFrame::DeselectAll)
341     EVT_MENU( ID_SELECT_CELL, GridFrame::SelectCell)
342     EVT_MENU( ID_SELECT_COL, GridFrame::SelectCol)
343     EVT_MENU( ID_SELECT_ROW, GridFrame::SelectRow)
344     EVT_MENU( ID_SELECT_ALL, GridFrame::SelectAll)
345     EVT_MENU( ID_SELECT_UNSELECT, GridFrame::OnAddToSelectToggle)
346 
347     EVT_MENU( ID_SIZE_ROW, GridFrame::AutoSizeRow )
348     EVT_MENU( ID_SIZE_COL, GridFrame::AutoSizeCol )
349     EVT_MENU( ID_SIZE_ROW_LABEL, GridFrame::AutoSizeRowLabel )
350     EVT_MENU( ID_SIZE_COL_LABEL, GridFrame::AutoSizeColLabel )
351     EVT_MENU( ID_SIZE_LABELS_COL, GridFrame::AutoSizeLabelsCol )
352     EVT_MENU( ID_SIZE_LABELS_ROW, GridFrame::AutoSizeLabelsRow )
353     EVT_MENU( ID_SIZE_GRID, GridFrame::AutoSizeTable )
354 
355     EVT_MENU( ID_HIDECOL, GridFrame::HideCol )
356     EVT_MENU( ID_SHOWCOL, GridFrame::ShowCol )
357     EVT_MENU( ID_HIDEROW, GridFrame::HideRow )
358     EVT_MENU( ID_SHOWROW, GridFrame::ShowRow )
359 
360     EVT_MENU( ID_SET_HIGHLIGHT_WIDTH, GridFrame::OnSetHighlightWidth)
361     EVT_MENU( ID_SET_RO_HIGHLIGHT_WIDTH, GridFrame::OnSetROHighlightWidth)
362 
363     EVT_MENU( wxID_PRINT, GridFrame::OnGridRender )
364     EVT_MENU( ID_RENDER_COORDS, GridFrame::OnGridRender )
365 
366     EVT_GRID_LABEL_LEFT_CLICK( GridFrame::OnLabelLeftClick )
367     EVT_GRID_CELL_LEFT_CLICK( GridFrame::OnCellLeftClick )
368     EVT_GRID_ROW_SIZE( GridFrame::OnRowSize )
369     EVT_GRID_COL_SIZE( GridFrame::OnColSize )
370     EVT_GRID_COL_AUTO_SIZE( GridFrame::OnColAutoSize )
371     EVT_GRID_SELECT_CELL( GridFrame::OnSelectCell )
372     EVT_GRID_RANGE_SELECTING( GridFrame::OnRangeSelecting )
373     EVT_GRID_RANGE_SELECTED( GridFrame::OnRangeSelected )
374     EVT_GRID_CELL_CHANGING( GridFrame::OnCellValueChanging )
375     EVT_GRID_CELL_CHANGED( GridFrame::OnCellValueChanged )
376     EVT_GRID_CELL_BEGIN_DRAG( GridFrame::OnCellBeginDrag )
377 
378     EVT_GRID_EDITOR_SHOWN( GridFrame::OnEditorShown )
379     EVT_GRID_EDITOR_HIDDEN( GridFrame::OnEditorHidden )
380 wxEND_EVENT_TABLE()
381 
382 
383 GridFrame::GridFrame()
384         : wxFrame( (wxFrame *)NULL, wxID_ANY, "wxWidgets grid class demo",
385                    wxDefaultPosition,
386                    wxDefaultSize )
387 {
388     SetIcon(wxICON(sample));
389 
390     wxMenu *fileMenu = new wxMenu;
391     fileMenu->Append( ID_VTABLE, "&Virtual table test\tCtrl-V");
392     fileMenu->Append( ID_BUGS_TABLE, "&Bugs table test\tCtrl-B");
393     fileMenu->Append( ID_TABULAR_TABLE, "&Tabular table test\tCtrl-T");
394     fileMenu->AppendSeparator();
395 
396     wxMenu* setupMenu = new wxMenu;
397     wxMenuItem* item;
398     item = setupMenu->AppendCheckItem( ID_RENDER_ROW_LABEL,
399                                        "Render row labels" );
400     item->Check();
401     item = setupMenu->AppendCheckItem( ID_RENDER_COL_LABEL,
402                                        "Render column labels" );
403     item->Check();
404     item = setupMenu->AppendCheckItem( ID_RENDER_GRID_LINES,
405                                        "Render grid cell lines" );
406     item->Check();
407     item = setupMenu->AppendCheckItem( ID_RENDER_GRID_BORDER,
408                                        "Render border" );
409     item->Check();
410     item = setupMenu->AppendCheckItem( ID_RENDER_SELECT_HLIGHT,
411                                        "Render selection highlight" );
412     setupMenu->AppendSeparator();
413     setupMenu->AppendCheckItem( ID_RENDER_LOMETRIC,
414                                        "Use LOMETRIC mapping mode" );
415     setupMenu->AppendCheckItem( ID_RENDER_DEFAULT_SIZE,
416                                        "Use wxDefaultSize" );
417     setupMenu->AppendCheckItem( ID_RENDER_MARGIN,
418                                 "Logical 50 unit margin" );
419     setupMenu->AppendCheckItem( ID_RENDER_ZOOM,
420                                 "Zoom 125%" );
421 
422     fileMenu->AppendSubMenu( setupMenu, "Render setup" );
423     fileMenu->Append( wxID_PRINT, "Render" );
424     fileMenu->Append( ID_RENDER_COORDS, "Render G5:P30" );
425 
426 #if wxUSE_LOG
427     fileMenu->AppendSeparator();
428     fileMenu->Append( wxID_CLEAR, "Clear &log\tCtrl-L" );
429 #endif // wxUSE_LOG
430 
431     fileMenu->AppendSeparator();
432     fileMenu->Append( wxID_EXIT, "E&xit\tAlt-X" );
433 
434     wxMenu *viewMenu = new wxMenu;
435     viewMenu->AppendCheckItem(ID_TOGGLEROWLABELS, "&Row labels");
436     viewMenu->AppendCheckItem(ID_TOGGLECOLLABELS, "&Col labels");
437     viewMenu->AppendCheckItem(ID_TOGGLEEDIT,"&Editable");
438     viewMenu->AppendCheckItem(ID_TOGGLEROWSIZING, "Ro&w drag-resize");
439     viewMenu->AppendCheckItem(ID_TOGGLECOLSIZING, "C&ol drag-resize");
440     viewMenu->AppendCheckItem(ID_TOGGLECOLMOVING, "Col drag-&move");
441     viewMenu->AppendCheckItem(ID_TOGGLECOLHIDING, "Col hiding popup menu");
442     viewMenu->AppendCheckItem(ID_TOGGLEGRIDSIZING, "&Grid drag-resize");
443     viewMenu->AppendCheckItem(ID_TOGGLEGRIDDRAGCELL, "&Grid drag-cell");
444     viewMenu->AppendCheckItem(ID_TOGGLEGRIDLINES, "&Grid Lines");
445     viewMenu->AppendCheckItem(ID_SET_HIGHLIGHT_WIDTH, "&Set Cell Highlight Width...");
446     viewMenu->AppendCheckItem(ID_SET_RO_HIGHLIGHT_WIDTH, "&Set Cell RO Highlight Width...");
447     viewMenu->AppendCheckItem(ID_AUTOSIZECOLS, "&Auto-size cols");
448     viewMenu->AppendCheckItem(ID_CELLOVERFLOW, "&Overflow cells");
449     viewMenu->AppendCheckItem(ID_RESIZECELL, "&Resize cell (7,1)");
450     viewMenu->AppendCheckItem(ID_TOGGLE_CHECKERED_CELLS,
451                               "Toggle Chec&kered Cells\tCtrl+Shift+K");
452     viewMenu->AppendCheckItem(ID_TOGGLE_COLOURED_CELLS,
453                               "Toggle Co&loured Cells\tCtrl+Shift+L");
454     viewMenu->Append(ID_HIDECOL, "&Hide column A");
455     viewMenu->Append(ID_SHOWCOL, "&Show column A");
456     viewMenu->Append(ID_HIDEROW, "&Hide row 2");
457     viewMenu->Append(ID_SHOWROW, "&Show row 2");
458     wxMenu *rowLabelMenu = new wxMenu;
459 
460     viewMenu->Append( ID_ROWLABELALIGN, "R&ow label alignment",
461                       rowLabelMenu,
462                       "Change alignment of row labels" );
463 
464     rowLabelMenu->AppendRadioItem( ID_ROWLABELHORIZALIGN, "&Horizontal" );
465     rowLabelMenu->AppendRadioItem( ID_ROWLABELVERTALIGN, "&Vertical" );
466 
467     wxMenu *colLabelMenu = new wxMenu;
468 
469     viewMenu->Append( ID_COLLABELALIGN, "Col l&abel alignment",
470                       colLabelMenu,
471                       "Change alignment of col labels" );
472 
473     colLabelMenu->AppendRadioItem( ID_COLLABELHORIZALIGN, "&Horizontal" );
474     colLabelMenu->AppendRadioItem( ID_COLLABELVERTALIGN, "&Vertical" );
475 
476     wxMenu *cornerLabelMenu = new wxMenu;
477     viewMenu->Append( ID_CORNERLABELALIGN, "Corner label alignment",
478                       cornerLabelMenu,
479                       "Change alignment of corner label" );
480 
481     cornerLabelMenu->AppendRadioItem( ID_CORNERLABELHORIZALIGN, "&Horizontal" );
482     cornerLabelMenu->AppendRadioItem( ID_CORNERLABELVERTALIGN, "&Vertical" );
483 
484     viewMenu->Append( ID_CORNERLABELORIENTATION, "Toggle corner label orientation" );
485 
486     wxMenu *colHeaderMenu = new wxMenu;
487 
488     viewMenu->Append( ID_ROWLABELALIGN, "Col header style",
489                       colHeaderMenu,
490                       "Change style of col header" );
491 
492     colHeaderMenu->AppendRadioItem( ID_COLDEFAULTHEADER, "&Default" );
493     colHeaderMenu->AppendRadioItem( ID_COLNATIVEHEADER, "&Native" );
494     colHeaderMenu->AppendRadioItem( ID_COLNATIVELABELS, "Native-&like" );
495     colHeaderMenu->AppendRadioItem( ID_COLCUSTOMHEADER, "&Custom" );
496 
497     wxMenu *tabBehaviourMenu = new wxMenu;
498     tabBehaviourMenu->AppendRadioItem(ID_TAB_STOP, "&Stop at the boundary");
499     tabBehaviourMenu->AppendRadioItem(ID_TAB_WRAP, "&Wrap at the boundary");
500     tabBehaviourMenu->AppendRadioItem(ID_TAB_LEAVE, "&Leave the grid");
501     tabBehaviourMenu->AppendRadioItem(ID_TAB_CUSTOM, "&Custom tab handler");
502     viewMenu->AppendSubMenu(tabBehaviourMenu, "&Tab behaviour");
503 
504     wxMenu *colMenu = new wxMenu;
505     colMenu->Append( ID_SETLABELCOLOUR, "Set &label colour..." );
506     colMenu->Append( ID_SETLABELTEXTCOLOUR, "Set label &text colour..." );
507     colMenu->Append( ID_SETLABEL_FONT, "Set label fo&nt..." );
508     colMenu->Append( ID_GRIDLINECOLOUR, "&Grid line colour..." );
509     colMenu->Append( ID_SET_CELL_FG_COLOUR, "Set cell &foreground colour..." );
510     colMenu->Append( ID_SET_CELL_BG_COLOUR, "Set cell &background colour..." );
511 
512     wxMenu *editMenu = new wxMenu;
513     editMenu->Append( ID_INSERTROW, "Insert &rows\tCtrl+I" );
514     editMenu->Append( ID_INSERTCOL, "Insert &columns\tCtrl+Shift+I" );
515     editMenu->Append( ID_DELETEROW, "Delete selected ro&ws\tCtrl+D" );
516     editMenu->Append( ID_DELETECOL, "Delete selected co&ls\tCtrl+Shift+D" );
517     editMenu->Append( ID_CLEARGRID, "Cl&ear grid cell contents" );
518     editMenu->Append( ID_EDITCELL, "&Edit current cell" );
519     editMenu->Append( ID_SETCORNERLABEL, "&Set corner label..." );
520 
521     editMenu->AppendCheckItem( ID_FREEZE_OR_THAW, "Freeze up to cursor\tCtrl-F" );
522 
523     wxMenu *selectMenu = new wxMenu;
524     selectMenu->Append( ID_SELECT_UNSELECT, "Add new cells to the selection",
525                         "When off, old selection is deselected before "
526                         "selecting the new cells", wxITEM_CHECK );
527     selectMenu->AppendSeparator();
528     selectMenu->Append( ID_SELECT_ALL, "Select all");
529     selectMenu->Append( ID_SELECT_ROW, "Select row 2");
530     selectMenu->Append( ID_SELECT_COL, "Select col 2");
531     selectMenu->Append( ID_SELECT_CELL, "Select cell (3, 1)");
532     selectMenu->AppendSeparator();
533     selectMenu->Append( ID_DESELECT_ALL, "Deselect all");
534     selectMenu->Append( ID_DESELECT_ROW, "Deselect row 2");
535     selectMenu->Append( ID_DESELECT_COL, "Deselect col 2");
536     selectMenu->Append( ID_DESELECT_CELL, "Deselect cell (3, 1)");
537     selectMenu->AppendSeparator();
538     wxMenu *selectionMenu = new wxMenu;
539     selectMenu->Append( ID_SHOWSEL, "&Show current selection\tCtrl-S" );
540     selectMenu->Append( ID_CHANGESEL, "Change &selection mode",
541                       selectionMenu,
542                       "Change selection mode" );
543 
544     selectionMenu->Append( ID_SELCELLS, "Select &cells" );
545     selectionMenu->Append( ID_SELROWS, "Select &rows" );
546     selectionMenu->Append( ID_SELCOLS, "Select col&umns" );
547     selectionMenu->Append( ID_SELROWSORCOLS, "Select rows &or columns" );
548     selectionMenu->Append( ID_SELNONE, "&Disallow selection" );
549 
550     wxMenu *autosizeMenu = new wxMenu;
551     autosizeMenu->Append( ID_SIZE_ROW, "Selected &row data" );
552     autosizeMenu->Append( ID_SIZE_COL, "Selected &column data" );
553     autosizeMenu->Append( ID_SIZE_ROW_LABEL, "Selected row la&bel" );
554     autosizeMenu->Append( ID_SIZE_COL_LABEL, "Selected column &label" );
555     autosizeMenu->Append( ID_SIZE_LABELS_COL, "Column la&bels" );
556     autosizeMenu->Append( ID_SIZE_LABELS_ROW, "Row label&s" );
557     autosizeMenu->Append( ID_SIZE_GRID, "Entire &grid" );
558 
559     wxMenu *helpMenu = new wxMenu;
560     helpMenu->Append( wxID_ABOUT, "&About wxGrid demo" );
561 
562     wxMenuBar *menuBar = new wxMenuBar;
563     menuBar->Append( fileMenu, "&File" );
564     menuBar->Append( viewMenu, "&Grid" );
565     menuBar->Append( colMenu,  "&Colours" );
566     menuBar->Append( editMenu, "&Edit" );
567     menuBar->Append( selectMenu, "&Select" );
568     menuBar->Append( autosizeMenu, "&Autosize" );
569     menuBar->Append( helpMenu, "&Help" );
570 
571     SetMenuBar( menuBar );
572 
573     m_addToSel = false;
574 
575     grid = new wxGrid( this,
576                        wxID_ANY,
577                        wxPoint( 0, 0 ),
578                        FromDIP(wxSize( 800, 450 )) );
579 
580 
581 #if wxUSE_LOG
582     logWin = new wxTextCtrl( this,
583                              wxID_ANY,
584                              wxEmptyString,
585                              wxDefaultPosition,
586                              wxSize(-1, 8*GetCharHeight()),
587                              wxTE_MULTILINE );
588 
589     logger = new wxLogTextCtrl( logWin );
590     m_logOld = wxLog::SetActiveTarget( logger );
591     wxLog::DisableTimestamp();
592 #endif // wxUSE_LOG
593 
594     // this will create a grid and, by default, an associated grid
595     // table for strings
596     grid->CreateGrid( 0, 0 );
597 
598     grid->GetTable()->SetAttrProvider(new CustomColumnHeadersProvider());
599 
600     grid->AppendRows(1000);
601     grid->AppendCols(100);
602 
603     int ir = grid->GetNumberRows();
604     grid->DeleteRows(0, ir);
605     grid->AppendRows(ir);
606 
607     grid->SetRowSize( 0, 4*grid->GetDefaultRowSize() );
608     grid->SetCellValue( 0, 0, "Ctrl+Home\nwill go to\nthis cell" );
609 
610     grid->SetCellValue( 0, 1, "A long piece of text to demonstrate wrapping." );
611     grid->SetCellRenderer(0 , 1, new wxGridCellAutoWrapStringRenderer);
612     grid->SetCellEditor( 0,  1 , new wxGridCellAutoWrapStringEditor);
613 
614     grid->SetCellValue( 0, 2, "Blah" );
615     grid->SetCellValue( 0, 3, "Read only" );
616     grid->SetReadOnly( 0, 3 );
617 
618     grid->SetCellValue( 0, 4, "Can veto edit this cell" );
619 
620     grid->SetColSize(10, FromDIP(150));
621     wxString longtext = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\n\n";
622     longtext += "With tabs :\n";
623     longtext += "Home,\t\thome\t\t\tagain\n";
624     longtext += "Long word at start :\n";
625     longtext += "ILikeToBeHereWhen I can\n";
626     longtext += "Long word in the middle :\n";
627     longtext += "When IComeHome,ColdAnd tired\n";
628     longtext += "Long last word :\n";
629     longtext += "It's GoodToWarmMyBonesBesideTheFire";
630     grid->SetCellValue( 0, 10, longtext );
631     grid->SetCellRenderer(0 , 10, new wxGridCellAutoWrapStringRenderer);
632     grid->SetCellEditor( 0,  10 , new wxGridCellAutoWrapStringEditor);
633     grid->SetCellValue( 0, 11, "K1 cell editor blocker" );
634 
635     grid->SetCellValue( 0, 5, "Press\nCtrl+arrow\nto skip over\ncells" );
636 
637     const int endRow = grid->GetNumberRows() - 1,
638               endCol = grid->GetNumberCols() - 1;
639 
640     grid->SetRowSize(endRow, 4 * grid->GetDefaultRowSize());
641     grid->SetCellValue(endRow - 1, endCol - 1, "Test background colour setting");
642     grid->SetCellBackgroundColour(endRow - 1, endCol, wxColour(255, 127, 127));
643     grid->SetCellBackgroundColour(endRow, endCol - 1, wxColour(255, 127, 127));
644     grid->SetCellValue(endRow, endCol, "Ctrl+End\nwill go to\nthis cell");
645     grid->SetCellValue( 1, 0, "This default cell will overflow into neighboring cells, but not if you turn overflow off.");
646 
647     grid->SetCellValue(2, 0, "This one always overflows");
648     grid->SetCellFitMode(2, 0, wxGridFitMode::Overflow());
649 
650     grid->SetCellTextColour(1, 2, *wxRED);
651     grid->SetCellBackgroundColour(1, 2, *wxGREEN);
652 
653     grid->SetCellValue( 1, 4, "I'm in the middle");
654 
655     grid->SetCellValue(2, 2, "red");
656 
657     grid->SetCellTextColour(2, 2, *wxRED);
658     grid->SetCellValue(3, 3, "green on grey");
659     grid->SetCellTextColour(3, 3, *wxGREEN);
660     grid->SetCellBackgroundColour(3, 3, *wxLIGHT_GREY);
661 
662     grid->SetCellValue(4, 4, "a weird looking cell");
663     grid->SetCellAlignment(4, 4, wxALIGN_CENTRE, wxALIGN_CENTRE);
664     grid->SetCellRenderer(4, 4, new MyGridCellRenderer);
665 
666     grid->SetCellValue(4, 5, "3");
667     grid->SetCellRenderer(4, 5, new MyGridStarRenderer);
668     grid->SetCellEditor(4, 5, new MyGridStarEditor);
669 
670     grid->SetCellRenderer(3, 0, new wxGridCellBoolRenderer);
671     grid->SetCellEditor(3, 0, new wxGridCellBoolEditor);
672     grid->SetCellBackgroundColour(3, 0, wxColour(255, 127, 127));
673 
674     grid->SetCellRenderer(3, 1, new wxGridCellBoolRenderer);
675     grid->SetCellEditor(3, 1, new wxGridCellBoolEditor);
676     grid->SetCellValue(3, 1, "1");
677 
678     wxGridCellAttr *attr;
679     attr = new wxGridCellAttr;
680     attr->SetTextColour(*wxBLUE);
681     grid->SetColAttr(5, attr);
682     attr = new wxGridCellAttr;
683     attr->SetBackgroundColour(*wxRED);
684     grid->SetRowAttr(5, attr);
685 
686     grid->SetCellValue(2, 4, "a wider column");
687     grid->SetColSize(4, 3*grid->GetDefaultColSize()/2);
688     grid->SetColMinimalWidth(4, grid->GetColSize(4));
689 
690     grid->SetCellTextColour(5, 8, *wxGREEN);
691     grid->SetCellValue(5, 8, "Bg from row attr\nText col from cell attr");
692     grid->SetCellValue(5, 5, "Bg from row attr Text col from col attr and this text is so long that it covers over many many empty cells but is broken by one that isn't");
693 
694     // Some numeric columns with different formatting.
695     grid->SetColFormatFloat(6);
696     grid->SetReadOnly(0, 6);
697     grid->SetCellValue(0, 6, "Default\nfloat format");
698     grid->SetCellValue(1, 6, wxString::Format("%g", 3.1415));
699     grid->SetCellValue(2, 6, wxString::Format("%g", 1415.0));
700     grid->SetCellValue(3, 6, wxString::Format("%g", 12345.67890));
701 
702     grid->SetColFormatFloat(7, 6, 2);
703     grid->SetReadOnly(0, 7);
704     grid->SetCellValue(0, 7, "Width 6\nprecision 2");
705     grid->SetCellValue(1, 7, wxString::Format("%g", 3.1415));
706     grid->SetCellValue(2, 7, wxString::Format("%g", 1415.0));
707     grid->SetCellValue(3, 7, wxString::Format("%g", 12345.67890));
708 
709     grid->SetColFormatCustom(8,
710             wxString::Format("%s:%i,%i,%s", wxGRID_VALUE_FLOAT, -1, 4, "g"));
711     grid->SetReadOnly(0, 8);
712     grid->SetCellValue(0, 8, "Compact\nformat");
713     grid->SetCellValue(1, 8, "31415e-4");
714     grid->SetCellValue(2, 8, "1415");
715     grid->SetCellValue(3, 8, "123456789e-4");
716 
717     grid->SetColFormatNumber(9);
718     grid->SetReadOnly(0, 9);
719     grid->SetCellValue(0, 9, "Integer\ncolumn");
720     grid->SetCellValue(1, 9, "17");
721     grid->SetCellValue(2, 9, "0");
722     grid->SetCellEditor(2, 9, new wxGridCellNumberEditor(0, 100));
723     grid->SetCellValue(2, 10, "<- This cell uses [0, 100] range");
724     grid->SetCellValue(3, 9, "-666");
725     grid->SetCellAlignment(3, 9, wxALIGN_CENTRE, wxALIGN_TOP);
726     grid->SetCellValue(3, 10, "<- This numeric cell should be centred");
727 
728     grid->SetReadOnly(0, 13);
729     grid->SetCellValue(0, 13, "Localized date\ncolumn");
730     grid->SetColFormatDate(13); // Localized by default.
731     grid->SetCellValue(1, 13, "Today");
732     grid->SetReadOnly(0, 14);
733     grid->SetCellValue(0, 14, "ISO 8601 date\ncolumn");
734     grid->SetColFormatDate(14, "%Y-%m-%d"); // ISO 8601 date format.
735     grid->SetCellValue(1, 14, "Tomorrow");
736 
737     grid->SetCellValue(13, 0, "Date cell:");
738     grid->SetCellValue(13, 1, "Today");
739     grid->SetCellRenderer(13, 1, new wxGridCellDateRenderer);
740     grid->SetCellEditor(13, 1, new wxGridCellDateEditor);
741     grid->SetCellValue(14, 0, "ISO date cell:");
742     grid->SetCellValue(14, 1, "Tomorrow");
743     grid->SetCellRenderer(14, 1, new wxGridCellDateRenderer("%Y-%m-%d"));
744     grid->SetCellEditor(14, 1, new wxGridCellDateEditor);
745 
746     grid->SetCellValue(13, 3, "String using default ellipsization");
747     grid->SetCellFitMode(13, 3, wxGridFitMode::Ellipsize());
748 
749     grid->SetCellValue(13, 4, "String ellipsized in the middle");
750     grid->SetCellFitMode(13, 4, wxGridFitMode::Ellipsize(wxELLIPSIZE_MIDDLE));
751 
752     const wxString choices[] =
753     {
754         "Please select a choice",
755         "This takes two cells",
756         "Another choice",
757     };
758     grid->SetCellEditor(4, 2, new wxGridCellChoiceEditor(WXSIZEOF(choices), choices));
759     grid->SetCellSize(4, 2, 1, 2);
760     grid->SetCellValue(4, 2, choices[0]);
761     grid->SetCellOverflow(4, 2, false);
762 
763     grid->SetCellSize(7, 1, 3, 4);
764     grid->SetCellAlignment(7, 1, wxALIGN_CENTRE, wxALIGN_CENTRE);
765     grid->SetCellValue(7, 1, "Big box!");
766 
767     // create a separator-like row: it's grey and it's non-resizable
768     grid->DisableRowResize(10);
769     grid->SetRowSize(10, 3*grid->GetDefaultRowSize()/2);
770     attr = new wxGridCellAttr;
771     attr->SetBackgroundColour(*wxLIGHT_GREY);
772     attr->SetAlignment(wxALIGN_INVALID, wxALIGN_CENTRE);
773     grid->SetRowAttr(10, attr);
774     grid->SetCellValue(10, 0, "You can't resize this row interactively -- try it");
775 
776     // this does exactly nothing except testing that SetAttr() handles NULL
777     // attributes and does reference counting correctly
778     grid->SetAttr(11, 11, NULL);
779     grid->SetAttr(11, 11, new wxGridCellAttr);
780     grid->SetAttr(11, 11, NULL);
781 
782     grid->Bind(wxEVT_CONTEXT_MENU, &GridFrame::OnGridContextMenu, this, grid->GetId());
783 
784     wxBoxSizer *topSizer = new wxBoxSizer( wxVERTICAL );
785     topSizer->Add(grid, wxSizerFlags(2).Expand());
786 
787 #if wxUSE_LOG
788     topSizer->Add(logWin, wxSizerFlags(1).Expand());
789 #endif // wxUSE_LOG
790 
791     SetSizerAndFit( topSizer );
792 
793     Centre();
794     SetDefaults();
795 }
796 
797 
~GridFrame()798 GridFrame::~GridFrame()
799 {
800 #if wxUSE_LOG
801     delete wxLog::SetActiveTarget(m_logOld);
802 #endif // wxUSE_LOG
803 }
804 
805 
SetDefaults()806 void GridFrame::SetDefaults()
807 {
808     GetMenuBar()->Check( ID_TOGGLEROWLABELS, true );
809     GetMenuBar()->Check( ID_TOGGLECOLLABELS, true );
810     GetMenuBar()->Check( ID_TOGGLEEDIT, true );
811     GetMenuBar()->Check( ID_TOGGLEROWSIZING, true );
812     GetMenuBar()->Check( ID_TOGGLECOLSIZING, true );
813     GetMenuBar()->Check( ID_TOGGLECOLMOVING, false );
814     GetMenuBar()->Check( ID_TOGGLECOLHIDING, true );
815     GetMenuBar()->Check( ID_TOGGLEGRIDSIZING, true );
816     GetMenuBar()->Check( ID_TOGGLEGRIDDRAGCELL, false );
817     GetMenuBar()->Check( ID_TOGGLEGRIDLINES, true );
818     GetMenuBar()->Check( ID_CELLOVERFLOW, true );
819 }
820 
821 
ToggleRowLabels(wxCommandEvent & WXUNUSED (ev))822 void GridFrame::ToggleRowLabels( wxCommandEvent& WXUNUSED(ev) )
823 {
824     if ( GetMenuBar()->IsChecked( ID_TOGGLEROWLABELS ) )
825     {
826         grid->SetRowLabelSize( grid->GetDefaultRowLabelSize() );
827     }
828     else
829     {
830         grid->SetRowLabelSize( 0 );
831     }
832 }
833 
834 
ToggleColLabels(wxCommandEvent & WXUNUSED (ev))835 void GridFrame::ToggleColLabels( wxCommandEvent& WXUNUSED(ev) )
836 {
837     if ( GetMenuBar()->IsChecked( ID_TOGGLECOLLABELS ) )
838     {
839         grid->SetColLabelSize( grid->GetDefaultColLabelSize() );
840     }
841     else
842     {
843         grid->SetColLabelSize( 0 );
844     }
845 }
846 
847 
ToggleEditing(wxCommandEvent & WXUNUSED (ev))848 void GridFrame::ToggleEditing( wxCommandEvent& WXUNUSED(ev) )
849 {
850     grid->EnableEditing(
851         GetMenuBar()->IsChecked( ID_TOGGLEEDIT ) );
852 }
853 
854 
ToggleRowSizing(wxCommandEvent & WXUNUSED (ev))855 void GridFrame::ToggleRowSizing( wxCommandEvent& WXUNUSED(ev) )
856 {
857     grid->EnableDragRowSize(
858         GetMenuBar()->IsChecked( ID_TOGGLEROWSIZING ) );
859 }
860 
861 
ToggleColSizing(wxCommandEvent & WXUNUSED (ev))862 void GridFrame::ToggleColSizing( wxCommandEvent& WXUNUSED(ev) )
863 {
864     grid->EnableDragColSize(
865         GetMenuBar()->IsChecked( ID_TOGGLECOLSIZING ) );
866 }
867 
ToggleColMoving(wxCommandEvent & WXUNUSED (ev))868 void GridFrame::ToggleColMoving( wxCommandEvent& WXUNUSED(ev) )
869 {
870     grid->EnableDragColMove(
871         GetMenuBar()->IsChecked( ID_TOGGLECOLMOVING ) );
872 }
873 
ToggleColHiding(wxCommandEvent & WXUNUSED (ev))874 void GridFrame::ToggleColHiding( wxCommandEvent& WXUNUSED(ev) )
875 {
876     if ( !grid->EnableHidingColumns(
877         GetMenuBar()->IsChecked( ID_TOGGLECOLHIDING ) ) )
878     {
879         GetMenuBar()->Check( ID_TOGGLECOLHIDING, grid->CanHideColumns() );
880     }
881 }
882 
ToggleGridSizing(wxCommandEvent & WXUNUSED (ev))883 void GridFrame::ToggleGridSizing( wxCommandEvent& WXUNUSED(ev) )
884 {
885     grid->EnableDragGridSize(
886         GetMenuBar()->IsChecked( ID_TOGGLEGRIDSIZING ) );
887 }
888 
ToggleGridDragCell(wxCommandEvent & WXUNUSED (ev))889 void GridFrame::ToggleGridDragCell( wxCommandEvent& WXUNUSED(ev) )
890 {
891     grid->EnableDragCell(
892         GetMenuBar()->IsChecked( ID_TOGGLEGRIDDRAGCELL ) );
893 }
894 
SetNativeColHeader(wxCommandEvent & WXUNUSED (ev))895 void GridFrame::SetNativeColHeader( wxCommandEvent& WXUNUSED(ev) )
896 {
897     CustomColumnHeadersProvider* provider =
898         static_cast<CustomColumnHeadersProvider*>(grid->GetTable()->GetAttrProvider());
899     provider->UseCustomColHeaders(false);
900     grid->UseNativeColHeader(true);
901 }
902 
SetNativeColLabels(wxCommandEvent & WXUNUSED (ev))903 void GridFrame::SetNativeColLabels( wxCommandEvent& WXUNUSED(ev) )
904 {
905     CustomColumnHeadersProvider* provider =
906         static_cast<CustomColumnHeadersProvider*>(grid->GetTable()->GetAttrProvider());
907     provider->UseCustomColHeaders(false);
908     grid->UseNativeColHeader(false);
909     grid->SetUseNativeColLabels(true);
910 }
911 
SetCustomColHeader(wxCommandEvent & WXUNUSED (ev))912 void GridFrame::SetCustomColHeader( wxCommandEvent& WXUNUSED(ev) )
913 {
914     CustomColumnHeadersProvider* provider =
915         static_cast<CustomColumnHeadersProvider*>(grid->GetTable()->GetAttrProvider());
916     provider->UseCustomColHeaders(true);
917     grid->UseNativeColHeader(false);
918     grid->SetUseNativeColLabels(false);
919 }
920 
SetDefaultColHeader(wxCommandEvent & WXUNUSED (ev))921 void GridFrame::SetDefaultColHeader( wxCommandEvent& WXUNUSED(ev) )
922 {
923     CustomColumnHeadersProvider* provider =
924         static_cast<CustomColumnHeadersProvider*>(grid->GetTable()->GetAttrProvider());
925     provider->UseCustomColHeaders(false);
926     grid->UseNativeColHeader(false);
927     grid->SetUseNativeColLabels(false);
928 }
929 
930 
OnGridCustomTab(wxGridEvent & event)931 void GridFrame::OnGridCustomTab(wxGridEvent& event)
932 {
933     // just for testing, make the cursor move up and down instead of the usual
934     // left and right
935     if ( event.ShiftDown() )
936     {
937         if ( grid->GetGridCursorRow() > 0 )
938             grid->MoveCursorUp( false );
939     }
940     else
941     {
942         if ( grid->GetGridCursorRow() < grid->GetNumberRows() - 1 )
943             grid->MoveCursorDown( false );
944     }
945 }
946 
SetTabBehaviour(wxCommandEvent & event)947 void GridFrame::SetTabBehaviour(wxCommandEvent& event)
948 {
949     // To make any built-in behaviour work, we need to disable the custom TAB
950     // handler, otherwise it would be overriding them.
951     grid->Unbind(wxEVT_GRID_TABBING, &GridFrame::OnGridCustomTab, this);
952 
953     grid->SetTabBehaviour(
954             static_cast<wxGrid::TabBehaviour>(event.GetId() - ID_TAB_STOP)
955         );
956 }
957 
SetTabCustomHandler(wxCommandEvent &)958 void GridFrame::SetTabCustomHandler(wxCommandEvent&)
959 {
960     grid->Bind(wxEVT_GRID_TABBING, &GridFrame::OnGridCustomTab, this);
961 }
962 
OnGridContextMenu(wxContextMenuEvent & event)963 void GridFrame::OnGridContextMenu(wxContextMenuEvent& event)
964 {
965     // This is not supposed to happen: even if the grid consists of different
966     // subwindows internally, all context menu events should be seen as coming
967     // from the grid itself.
968     if ( event.GetEventObject() != grid )
969     {
970         wxLogError("Context menu unexpectedly sent from non-grid window.");
971     }
972     else
973     {
974         wxLogMessage("wxEVT_CONTEXT_MENU in the grid at at (%d, %d)",
975                      event.GetPosition().x, event.GetPosition().y);
976     }
977 
978     event.Skip();
979 }
980 
ToggleGridLines(wxCommandEvent & WXUNUSED (ev))981 void GridFrame::ToggleGridLines( wxCommandEvent& WXUNUSED(ev) )
982 {
983     grid->EnableGridLines(
984         GetMenuBar()->IsChecked( ID_TOGGLEGRIDLINES ) );
985 }
986 
OnSetHighlightWidth(wxCommandEvent & WXUNUSED (ev))987 void GridFrame::OnSetHighlightWidth( wxCommandEvent& WXUNUSED(ev) )
988 {
989     wxString choices[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"};
990 
991     wxSingleChoiceDialog dlg(this, "Choose the thickness of the highlight pen:",
992                              "Pen Width", 11, choices);
993 
994     int current = grid->GetCellHighlightPenWidth();
995     dlg.SetSelection(current);
996     if (dlg.ShowModal() == wxID_OK) {
997         grid->SetCellHighlightPenWidth(dlg.GetSelection());
998     }
999 }
1000 
OnSetROHighlightWidth(wxCommandEvent & WXUNUSED (ev))1001 void GridFrame::OnSetROHighlightWidth( wxCommandEvent& WXUNUSED(ev) )
1002 {
1003     wxString choices[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"};
1004 
1005     wxSingleChoiceDialog dlg(this, "Choose the thickness of the highlight pen:",
1006                              "Pen Width", 11, choices);
1007 
1008     int current = grid->GetCellHighlightROPenWidth();
1009     dlg.SetSelection(current);
1010     if (dlg.ShowModal() == wxID_OK) {
1011         grid->SetCellHighlightROPenWidth(dlg.GetSelection());
1012     }
1013 }
1014 
1015 
1016 
AutoSizeCols(wxCommandEvent & WXUNUSED (ev))1017 void GridFrame::AutoSizeCols( wxCommandEvent& WXUNUSED(ev) )
1018 {
1019     grid->AutoSizeColumns();
1020     grid->Refresh();
1021 }
1022 
CellOverflow(wxCommandEvent & ev)1023 void GridFrame::CellOverflow( wxCommandEvent& ev )
1024 {
1025     grid->SetDefaultCellOverflow(ev.IsChecked());
1026     grid->Refresh();
1027 }
1028 
ResizeCell(wxCommandEvent & ev)1029 void GridFrame::ResizeCell( wxCommandEvent& ev )
1030 {
1031     if (ev.IsChecked())
1032         grid->SetCellSize( 7, 1, 5, 5 );
1033     else
1034         grid->SetCellSize( 7, 1, 1, 5 );
1035     grid->Refresh();
1036 }
1037 
SetLabelColour(wxCommandEvent & WXUNUSED (ev))1038 void GridFrame::SetLabelColour( wxCommandEvent& WXUNUSED(ev) )
1039 {
1040     wxColourDialog dlg( NULL );
1041     if ( dlg.ShowModal() == wxID_OK )
1042     {
1043         wxColourData retData;
1044         retData = dlg.GetColourData();
1045         wxColour colour = retData.GetColour();
1046 
1047         grid->SetLabelBackgroundColour( colour );
1048     }
1049 }
1050 
1051 
SetLabelTextColour(wxCommandEvent & WXUNUSED (ev))1052 void GridFrame::SetLabelTextColour( wxCommandEvent& WXUNUSED(ev) )
1053 {
1054     wxColourDialog dlg( NULL );
1055     if ( dlg.ShowModal() == wxID_OK )
1056     {
1057         wxColourData retData;
1058         retData = dlg.GetColourData();
1059         wxColour colour = retData.GetColour();
1060 
1061         grid->SetLabelTextColour( colour );
1062     }
1063 }
1064 
SetLabelFont(wxCommandEvent & WXUNUSED (ev))1065 void GridFrame::SetLabelFont( wxCommandEvent& WXUNUSED(ev) )
1066 {
1067     wxFont font = wxGetFontFromUser(this);
1068     if ( font.IsOk() )
1069     {
1070         grid->SetLabelFont(font);
1071     }
1072 }
1073 
SetRowLabelHorizAlignment(wxCommandEvent & WXUNUSED (ev))1074 void GridFrame::SetRowLabelHorizAlignment( wxCommandEvent& WXUNUSED(ev) )
1075 {
1076     int horiz, vert;
1077     grid->GetRowLabelAlignment( &horiz, &vert );
1078 
1079     switch ( horiz )
1080     {
1081         case wxALIGN_LEFT:
1082             horiz = wxALIGN_CENTRE;
1083             break;
1084 
1085         case wxALIGN_CENTRE:
1086             horiz = wxALIGN_RIGHT;
1087             break;
1088 
1089         case wxALIGN_RIGHT:
1090             horiz = wxALIGN_LEFT;
1091             break;
1092     }
1093 
1094     grid->SetRowLabelAlignment( horiz, vert );
1095 }
1096 
SetRowLabelVertAlignment(wxCommandEvent & WXUNUSED (ev))1097 void GridFrame::SetRowLabelVertAlignment( wxCommandEvent& WXUNUSED(ev) )
1098 {
1099     int horiz, vert;
1100     grid->GetRowLabelAlignment( &horiz, &vert );
1101 
1102     switch ( vert )
1103     {
1104         case wxALIGN_TOP:
1105             vert = wxALIGN_CENTRE;
1106             break;
1107 
1108         case wxALIGN_CENTRE:
1109             vert = wxALIGN_BOTTOM;
1110             break;
1111 
1112         case wxALIGN_BOTTOM:
1113             vert = wxALIGN_TOP;
1114             break;
1115     }
1116 
1117     grid->SetRowLabelAlignment( horiz, vert );
1118 }
1119 
1120 
SetColLabelHorizAlignment(wxCommandEvent & WXUNUSED (ev))1121 void GridFrame::SetColLabelHorizAlignment( wxCommandEvent& WXUNUSED(ev) )
1122 {
1123     int horiz, vert;
1124     grid->GetColLabelAlignment( &horiz, &vert );
1125 
1126     switch ( horiz )
1127     {
1128         case wxALIGN_LEFT:
1129             horiz = wxALIGN_CENTRE;
1130             break;
1131 
1132         case wxALIGN_CENTRE:
1133             horiz = wxALIGN_RIGHT;
1134             break;
1135 
1136         case wxALIGN_RIGHT:
1137             horiz = wxALIGN_LEFT;
1138             break;
1139     }
1140 
1141     grid->SetColLabelAlignment( horiz, vert );
1142 }
1143 
1144 
SetColLabelVertAlignment(wxCommandEvent & WXUNUSED (ev))1145 void GridFrame::SetColLabelVertAlignment( wxCommandEvent& WXUNUSED(ev) )
1146 {
1147     int horiz, vert;
1148     grid->GetColLabelAlignment( &horiz, &vert );
1149 
1150     switch ( vert )
1151     {
1152         case wxALIGN_TOP:
1153             vert = wxALIGN_CENTRE;
1154             break;
1155 
1156         case wxALIGN_CENTRE:
1157             vert = wxALIGN_BOTTOM;
1158             break;
1159 
1160         case wxALIGN_BOTTOM:
1161             vert = wxALIGN_TOP;
1162             break;
1163     }
1164 
1165     grid->SetColLabelAlignment( horiz, vert );
1166 }
1167 
1168 
SetCornerLabelHorizAlignment(wxCommandEvent & WXUNUSED (ev))1169 void GridFrame::SetCornerLabelHorizAlignment( wxCommandEvent& WXUNUSED(ev) )
1170 {
1171     int horiz, vert;
1172     grid->GetCornerLabelAlignment( &horiz, &vert );
1173 
1174     switch ( horiz )
1175     {
1176         case wxALIGN_LEFT:
1177             horiz = wxALIGN_CENTRE;
1178             break;
1179 
1180         case wxALIGN_CENTRE:
1181             horiz = wxALIGN_RIGHT;
1182             break;
1183 
1184         case wxALIGN_RIGHT:
1185             horiz = wxALIGN_LEFT;
1186             break;
1187     }
1188 
1189     grid->SetCornerLabelAlignment( horiz, vert );
1190 }
1191 
1192 
SetCornerLabelVertAlignment(wxCommandEvent & WXUNUSED (ev))1193 void GridFrame::SetCornerLabelVertAlignment( wxCommandEvent& WXUNUSED(ev) )
1194 {
1195     int horiz, vert;
1196     grid->GetCornerLabelAlignment( &horiz, &vert );
1197 
1198     switch ( vert )
1199     {
1200         case wxALIGN_TOP:
1201             vert = wxALIGN_CENTRE;
1202             break;
1203 
1204         case wxALIGN_CENTRE:
1205             vert = wxALIGN_BOTTOM;
1206             break;
1207 
1208         case wxALIGN_BOTTOM:
1209             vert = wxALIGN_TOP;
1210             break;
1211     }
1212 
1213     grid->SetCornerLabelAlignment( horiz, vert );
1214 }
1215 
1216 
ToggleCornerLabelOrientation(wxCommandEvent & WXUNUSED (ev))1217 void GridFrame::ToggleCornerLabelOrientation( wxCommandEvent& WXUNUSED(ev) )
1218 {
1219     int orientation = grid->GetCornerLabelTextOrientation();
1220 
1221     switch(orientation)
1222     {
1223         case wxHORIZONTAL:
1224             orientation = wxVERTICAL;
1225             break;
1226 
1227         case wxVERTICAL:
1228             orientation = wxHORIZONTAL;
1229             break;
1230     }
1231 
1232     grid->SetCornerLabelTextOrientation(orientation);
1233 }
1234 
1235 
SetGridLineColour(wxCommandEvent & WXUNUSED (ev))1236 void GridFrame::SetGridLineColour( wxCommandEvent& WXUNUSED(ev) )
1237 {
1238     wxColourDialog dlg( NULL );
1239     if ( dlg.ShowModal() == wxID_OK )
1240     {
1241         wxColourData retData;
1242         retData = dlg.GetColourData();
1243         wxColour colour = retData.GetColour();
1244 
1245         grid->SetGridLineColour( colour );
1246     }
1247 }
1248 
1249 namespace
1250 {
1251 
1252 // Helper used to insert/delete rows/columns. Allows changing by more than
1253 // one row/column at once.
HandleEdits(wxGrid * grid,wxGridDirection direction,bool isInsertion)1254 void HandleEdits(wxGrid* grid, wxGridDirection direction, bool isInsertion)
1255 {
1256     const bool isRow = (direction == wxGRID_ROW);
1257 
1258     const wxGridBlocks selected = grid->GetSelectedBlocks();
1259     wxGridBlocks::iterator it = selected.begin();
1260 
1261     if ( isInsertion )
1262     {
1263         int pos, count;
1264         // Only do multiple insertions if we have a single consecutive
1265         // selection (mimicking LibreOffice), otherwise do a single insertion
1266         // at cursor.
1267         if ( it != selected.end() && ++it == selected.end() )
1268         {
1269             const wxGridBlockCoords& b = *selected.begin();
1270             pos = isRow ? b.GetTopRow() : b.GetLeftCol();
1271             count = (isRow ? b.GetBottomRow() : b.GetRightCol()) - pos + 1;
1272         }
1273         else
1274         {
1275             pos = isRow ? grid->GetGridCursorRow() : grid->GetGridCursorCol();
1276             count = 1;
1277         }
1278 
1279         if ( isRow )
1280             grid->InsertRows(pos, count);
1281         else
1282             grid->InsertCols(pos, count);
1283 
1284         return;
1285     }
1286 
1287     wxGridUpdateLocker locker(grid);
1288 
1289     wxVector<int> deletions;
1290 
1291     for (; it != selected.end(); ++it )
1292     {
1293         const wxGridBlockCoords& b = *it;
1294         const int begin = isRow ? b.GetTopRow() : b.GetLeftCol();
1295         const int end = isRow ? b.GetBottomRow() : b.GetRightCol();
1296 
1297         for ( int n = begin; n <= end; ++n )
1298         {
1299             if ( !wxVectorContains(deletions, n) )
1300                 deletions.push_back(n);
1301         }
1302     }
1303 
1304     wxVectorSort(deletions);
1305 
1306     const size_t deletionCount = deletions.size();
1307 
1308     if ( !deletionCount )
1309         return;
1310 
1311     int seqEnd = 0, seqCount = 0;
1312     for ( size_t i = deletionCount; i > 0; --i )
1313     {
1314         const int n = deletions[i - 1];
1315 
1316         if ( n != seqEnd - seqCount )
1317         {
1318             if (i != deletionCount)
1319             {
1320                 const int seqStart = seqEnd - seqCount + 1;
1321                 if ( isRow )
1322                     grid->DeleteRows(seqStart, seqCount);
1323                 else
1324                     grid->DeleteCols(seqStart, seqCount);
1325             }
1326 
1327             seqEnd = n;
1328             seqCount = 0;
1329         }
1330 
1331         seqCount++;
1332     }
1333 
1334     const int seqStart = seqEnd - seqCount + 1;
1335     if ( isRow )
1336         grid->DeleteRows(seqStart, seqCount);
1337     else
1338         grid->DeleteCols(seqStart, seqCount);
1339 }
1340 
1341 } // anoymous namespace
1342 
InsertRow(wxCommandEvent & WXUNUSED (ev))1343 void GridFrame::InsertRow( wxCommandEvent& WXUNUSED(ev) )
1344 {
1345     HandleEdits(grid, wxGRID_ROW, /* isInsertion = */ true);
1346 }
1347 
1348 
InsertCol(wxCommandEvent & WXUNUSED (ev))1349 void GridFrame::InsertCol( wxCommandEvent& WXUNUSED(ev) )
1350 {
1351     HandleEdits(grid, wxGRID_COLUMN, /* isInsertion = */ true);
1352 }
1353 
1354 
DeleteSelectedRows(wxCommandEvent & WXUNUSED (ev))1355 void GridFrame::DeleteSelectedRows( wxCommandEvent& WXUNUSED(ev) )
1356 {
1357     HandleEdits(grid, wxGRID_ROW, /* isInsertion = */ false);
1358 }
1359 
1360 
AutoSizeRow(wxCommandEvent & WXUNUSED (event))1361 void GridFrame::AutoSizeRow(wxCommandEvent& WXUNUSED(event))
1362 {
1363     wxGridUpdateLocker locker(grid);
1364     const wxArrayInt sels  = grid->GetSelectedRows();
1365     for ( size_t n = 0, count = sels.size(); n < count; n++ )
1366     {
1367         grid->AutoSizeRow( sels[n], false );
1368     }
1369 }
1370 
AutoSizeCol(wxCommandEvent & WXUNUSED (event))1371 void GridFrame::AutoSizeCol(wxCommandEvent& WXUNUSED(event))
1372 {
1373     wxGridUpdateLocker locker(grid);
1374     const wxArrayInt sels  = grid->GetSelectedCols();
1375     for ( size_t n = 0, count = sels.size(); n < count; n++ )
1376     {
1377         grid->AutoSizeColumn( sels[n], false );
1378     }
1379 }
1380 
AutoSizeRowLabel(wxCommandEvent & WXUNUSED (event))1381 void GridFrame::AutoSizeRowLabel(wxCommandEvent& WXUNUSED(event))
1382 {
1383     wxGridUpdateLocker locker(grid);
1384     const wxArrayInt sels  = grid->GetSelectedRows();
1385     for ( size_t n = 0, count = sels.size(); n < count; n++ )
1386     {
1387         grid->AutoSizeRowLabelSize( sels[n] );
1388     }
1389 }
1390 
AutoSizeColLabel(wxCommandEvent & WXUNUSED (event))1391 void GridFrame::AutoSizeColLabel(wxCommandEvent& WXUNUSED(event))
1392 {
1393     wxGridUpdateLocker locker(grid);
1394     const wxArrayInt sels  = grid->GetSelectedCols();
1395     for ( size_t n = 0, count = sels.size(); n < count; n++ )
1396     {
1397         grid->AutoSizeColLabelSize( sels[n] );
1398     }
1399 }
1400 
AutoSizeLabelsCol(wxCommandEvent & WXUNUSED (event))1401 void GridFrame::AutoSizeLabelsCol(wxCommandEvent& WXUNUSED(event))
1402 {
1403     grid->SetColLabelSize( wxGRID_AUTOSIZE );
1404 }
1405 
AutoSizeLabelsRow(wxCommandEvent & WXUNUSED (event))1406 void GridFrame::AutoSizeLabelsRow(wxCommandEvent& WXUNUSED(event))
1407 {
1408     grid->SetRowLabelSize( wxGRID_AUTOSIZE );
1409 }
1410 
AutoSizeTable(wxCommandEvent & WXUNUSED (event))1411 void GridFrame::AutoSizeTable(wxCommandEvent& WXUNUSED(event))
1412 {
1413     grid->AutoSize();
1414     Layout();
1415 }
1416 
1417 
DeleteSelectedCols(wxCommandEvent & WXUNUSED (ev))1418 void GridFrame::DeleteSelectedCols( wxCommandEvent& WXUNUSED(ev) )
1419 {
1420     HandleEdits(grid, wxGRID_COLUMN, /* isInsertion = */ false);
1421 }
1422 
1423 
ClearGrid(wxCommandEvent & WXUNUSED (ev))1424 void GridFrame::ClearGrid( wxCommandEvent& WXUNUSED(ev) )
1425 {
1426     grid->ClearGrid();
1427 }
1428 
EditCell(wxCommandEvent & WXUNUSED (ev))1429 void GridFrame::EditCell( wxCommandEvent& WXUNUSED(ev) )
1430 {
1431     grid->EnableCellEditControl();
1432 }
1433 
SetCornerLabelValue(wxCommandEvent & WXUNUSED (ev))1434 void GridFrame::SetCornerLabelValue( wxCommandEvent& WXUNUSED(ev) )
1435 {
1436     wxTextEntryDialog dialog(this,
1437                              "Please enter corner label:",
1438                              "Please enter a string",
1439                              grid->GetCornerLabelValue(),
1440                              wxOK | wxCANCEL);
1441 
1442     if (dialog.ShowModal() == wxID_OK)
1443     {
1444         grid->SetCornerLabelValue(dialog.GetValue());
1445     }
1446 }
1447 
ShowSelection(wxCommandEvent & WXUNUSED (ev))1448 void GridFrame::ShowSelection( wxCommandEvent& WXUNUSED(ev) )
1449 {
1450     int count = 0;
1451     wxString desc;
1452     const wxGridBlocks& sel = grid->GetSelectedBlocks();
1453     for ( wxGridBlocks::iterator it = sel.begin(); it != sel.end(); ++it )
1454     {
1455         const wxGridBlockCoords& b = *it;
1456 
1457         wxString blockDesc;
1458         if ( b.GetLeftCol() == 0 &&
1459                 b.GetRightCol() == grid->GetNumberCols() - 1 )
1460         {
1461             if ( b.GetTopRow() == b.GetBottomRow() )
1462                 blockDesc.Printf("row %d", b.GetTopRow() + 1);
1463             else
1464                 blockDesc.Printf("rows %d..%d",
1465                                  b.GetTopRow() + 1, b.GetBottomRow() + 1);
1466         }
1467         else if ( b.GetTopRow() == 0 &&
1468                         b.GetBottomRow() == grid->GetNumberRows() - 1 )
1469         {
1470             if ( b.GetLeftCol() == b.GetRightCol() )
1471                 blockDesc.Printf("column %d", b.GetLeftCol() + 1);
1472             else
1473                 blockDesc.Printf("columns %d..%d",
1474                                  b.GetLeftCol() + 1,
1475                                  b.GetRightCol() + 1);
1476         }
1477         else if ( b.GetTopRow() == b.GetBottomRow() &&
1478                     b.GetLeftCol() == b.GetRightCol() )
1479         {
1480             blockDesc.Printf("cell R%dC%d",
1481                              b.GetTopRow() + 1, b.GetLeftCol() + 1);
1482         }
1483         else
1484         {
1485             blockDesc.Printf("block R%dC%d - R%dC%d",
1486                              b.GetTopRow() + 1,
1487                              b.GetLeftCol() + 1,
1488                              b.GetBottomRow() + 1,
1489                              b.GetRightCol() + 1);
1490         }
1491 
1492         if ( count++ )
1493             desc += "\n\t";
1494         desc += blockDesc;
1495     }
1496 
1497     switch ( count )
1498     {
1499         case 0:
1500             wxLogMessage("No selection");
1501             break;
1502 
1503         case 1:
1504             wxLogMessage("Selection: %s", desc);
1505             break;
1506 
1507         default:
1508             wxLogMessage("%d selected blocks:\n\t%s", count, desc);
1509     }
1510 }
1511 
SelectCells(wxCommandEvent & WXUNUSED (ev))1512 void GridFrame::SelectCells( wxCommandEvent& WXUNUSED(ev) )
1513 {
1514     grid->SetSelectionMode( wxGrid::wxGridSelectCells );
1515 }
1516 
SelectRows(wxCommandEvent & WXUNUSED (ev))1517 void GridFrame::SelectRows( wxCommandEvent& WXUNUSED(ev) )
1518 {
1519     grid->SetSelectionMode( wxGrid::wxGridSelectRows );
1520 }
1521 
SelectCols(wxCommandEvent & WXUNUSED (ev))1522 void GridFrame::SelectCols( wxCommandEvent& WXUNUSED(ev) )
1523 {
1524     grid->SetSelectionMode( wxGrid::wxGridSelectColumns );
1525 }
1526 
SelectRowsOrCols(wxCommandEvent & WXUNUSED (ev))1527 void GridFrame::SelectRowsOrCols( wxCommandEvent& WXUNUSED(ev) )
1528 {
1529     grid->SetSelectionMode( wxGrid::wxGridSelectRowsOrColumns );
1530 }
1531 
SelectNone(wxCommandEvent & WXUNUSED (ev))1532 void GridFrame::SelectNone( wxCommandEvent& WXUNUSED(ev) )
1533 {
1534     grid->SetSelectionMode( wxGrid::wxGridSelectNone );
1535 }
1536 
FreezeOrThaw(wxCommandEvent & ev)1537 void GridFrame::FreezeOrThaw(wxCommandEvent& ev)
1538 {
1539     if ( ev.IsChecked() )
1540     {
1541         if ( !grid->FreezeTo(grid->GetGridCursorCoords()) )
1542         {
1543             wxLogMessage("Failed to freeze the grid.");
1544             GetMenuBar()->Check(ID_FREEZE_OR_THAW, false);
1545             return;
1546         }
1547 
1548         wxLogMessage("Grid is now frozen");
1549     }
1550     else
1551     {
1552         // This never fails.
1553         grid->FreezeTo(0, 0);
1554 
1555         wxLogMessage("Grid is now thawed");
1556     }
1557 
1558     GetMenuBar()->Enable( ID_TOGGLECOLMOVING, !grid->IsFrozen() );
1559 }
1560 
SetCellFgColour(wxCommandEvent & WXUNUSED (ev))1561 void GridFrame::SetCellFgColour( wxCommandEvent& WXUNUSED(ev) )
1562 {
1563     wxColour col = wxGetColourFromUser(this);
1564     if ( col.IsOk() )
1565     {
1566         grid->SetDefaultCellTextColour(col);
1567         grid->Refresh();
1568     }
1569 }
1570 
SetCellBgColour(wxCommandEvent & WXUNUSED (ev))1571 void GridFrame::SetCellBgColour( wxCommandEvent& WXUNUSED(ev) )
1572 {
1573     wxColour col = wxGetColourFromUser(this);
1574     if ( col.IsOk() )
1575     {
1576         // Check the new Refresh function by passing it a rectangle
1577         // which exactly fits the grid.
1578         wxPoint pt(0, 0);
1579         wxRect r(pt, grid->GetSize());
1580         grid->SetDefaultCellBackgroundColour(col);
1581         grid->Refresh(true, &r);
1582     }
1583 }
1584 
DeselectCell(wxCommandEvent & WXUNUSED (event))1585 void GridFrame::DeselectCell(wxCommandEvent& WXUNUSED(event))
1586 {
1587       grid->DeselectCell(3, 1);
1588 }
1589 
DeselectCol(wxCommandEvent & WXUNUSED (event))1590 void GridFrame::DeselectCol(wxCommandEvent& WXUNUSED(event))
1591 {
1592       grid->DeselectCol(2);
1593 }
1594 
DeselectRow(wxCommandEvent & WXUNUSED (event))1595 void GridFrame::DeselectRow(wxCommandEvent& WXUNUSED(event))
1596 {
1597       grid->DeselectRow(2);
1598 }
1599 
DeselectAll(wxCommandEvent & WXUNUSED (event))1600 void GridFrame::DeselectAll(wxCommandEvent& WXUNUSED(event))
1601 {
1602       grid->ClearSelection();
1603 }
1604 
SelectCell(wxCommandEvent & WXUNUSED (event))1605 void GridFrame::SelectCell(wxCommandEvent& WXUNUSED(event))
1606 {
1607       grid->SelectBlock(3, 1, 3, 1, m_addToSel);
1608 }
1609 
SelectCol(wxCommandEvent & WXUNUSED (event))1610 void GridFrame::SelectCol(wxCommandEvent& WXUNUSED(event))
1611 {
1612       grid->SelectCol(2, m_addToSel);
1613 }
1614 
SelectRow(wxCommandEvent & WXUNUSED (event))1615 void GridFrame::SelectRow(wxCommandEvent& WXUNUSED(event))
1616 {
1617       grid->SelectRow(2, m_addToSel);
1618 }
1619 
SelectAll(wxCommandEvent & WXUNUSED (event))1620 void GridFrame::SelectAll(wxCommandEvent& WXUNUSED(event))
1621 {
1622       grid->SelectAll();
1623 }
1624 
OnAddToSelectToggle(wxCommandEvent & event)1625 void GridFrame::OnAddToSelectToggle(wxCommandEvent& event)
1626 {
1627     m_addToSel = event.IsChecked();
1628 }
1629 
OnLabelLeftClick(wxGridEvent & ev)1630 void GridFrame::OnLabelLeftClick( wxGridEvent& ev )
1631 {
1632     wxString logBuf;
1633     if ( ev.GetRow() != -1 )
1634     {
1635         logBuf << "Left click on row label " << ev.GetRow();
1636     }
1637     else if ( ev.GetCol() != -1 )
1638     {
1639         logBuf << "Left click on col label " << ev.GetCol();
1640     }
1641     else
1642     {
1643         logBuf << "Left click on corner label";
1644     }
1645 
1646     if ( ev.ShiftDown() )
1647         logBuf << " (shift down)";
1648     if ( ev.ControlDown() )
1649         logBuf << " (control down)";
1650     wxLogMessage( "%s", logBuf );
1651 
1652     // you must call event skip if you want default grid processing
1653     //
1654     ev.Skip();
1655 }
1656 
1657 
OnCellLeftClick(wxGridEvent & ev)1658 void GridFrame::OnCellLeftClick( wxGridEvent& ev )
1659 {
1660     wxLogMessage("Left click at row %d, col %d", ev.GetRow(), ev.GetCol());
1661 
1662     // you must call event skip if you want default grid processing
1663     // (cell highlighting etc.)
1664     //
1665     ev.Skip();
1666 }
1667 
1668 
OnRowSize(wxGridSizeEvent & ev)1669 void GridFrame::OnRowSize( wxGridSizeEvent& ev )
1670 {
1671     const int row = ev.GetRowOrCol();
1672 
1673     wxLogMessage("Resized row %d, new height = %d",
1674                  row, grid->GetRowSize(row));
1675 
1676     ev.Skip();
1677 }
1678 
1679 
OnColSize(wxGridSizeEvent & ev)1680 void GridFrame::OnColSize( wxGridSizeEvent& ev )
1681 {
1682     const int col = ev.GetRowOrCol();
1683 
1684     wxLogMessage("Resized column %d, new width = %d",
1685                  col, grid->GetColSize(col));
1686 
1687     ev.Skip();
1688 }
1689 
OnColAutoSize(wxGridSizeEvent & event)1690 void GridFrame::OnColAutoSize( wxGridSizeEvent &event )
1691 {
1692     // Fit even-numbered columns to their contents while using the default
1693     // behaviour for the odd-numbered ones to be able to see the difference.
1694     int col = event.GetRowOrCol();
1695     if ( col % 2 )
1696     {
1697         wxLogMessage("Auto-sizing column %d to fit its contents", col);
1698         grid->AutoSizeColumn(col);
1699     }
1700     else
1701     {
1702         event.Skip();
1703     }
1704 }
1705 
OnSelectCell(wxGridEvent & ev)1706 void GridFrame::OnSelectCell( wxGridEvent& ev )
1707 {
1708     wxString logBuf;
1709     if ( ev.Selecting() )
1710         logBuf << "Selected ";
1711     else
1712         logBuf << "Deselected ";
1713     logBuf << "cell at row " << ev.GetRow()
1714            << " col " << ev.GetCol()
1715            << " ( ControlDown: "<< (ev.ControlDown() ? 'T':'F')
1716            << ", ShiftDown: "<< (ev.ShiftDown() ? 'T':'F')
1717            << ", AltDown: "<< (ev.AltDown() ? 'T':'F')
1718            << ", MetaDown: "<< (ev.MetaDown() ? 'T':'F') << " )";
1719 
1720     //Indicate whether this column was moved
1721     if ( ((wxGrid *)ev.GetEventObject())->GetColPos( ev.GetCol() ) != ev.GetCol() )
1722         logBuf << " *** Column moved, current position: " << ((wxGrid *)ev.GetEventObject())->GetColPos( ev.GetCol() );
1723 
1724     wxLogMessage( "%s", logBuf );
1725 
1726     // you must call Skip() if you want the default processing
1727     // to occur in wxGrid
1728     ev.Skip();
1729 }
1730 
1731 namespace
1732 {
1733 
1734 void
LogRangeSelectEvent(wxGridRangeSelectEvent & ev,const char * suffix)1735 LogRangeSelectEvent(wxGridRangeSelectEvent& ev, const char* suffix)
1736 {
1737     wxString logBuf;
1738     if ( ev.Selecting() )
1739         logBuf << "Select";
1740     else
1741         logBuf << "Deselect";
1742     logBuf << suffix
1743            << " cells from row " << ev.GetTopRow()
1744            << " col " << ev.GetLeftCol()
1745            << " to row " << ev.GetBottomRow()
1746            << " col " << ev.GetRightCol()
1747            << " ( ControlDown: "<< (ev.ControlDown() ? 'T':'F')
1748            << ", ShiftDown: "<< (ev.ShiftDown() ? 'T':'F')
1749            << ", AltDown: "<< (ev.AltDown() ? 'T':'F')
1750            << ", MetaDown: "<< (ev.MetaDown() ? 'T':'F') << " )";
1751     wxLogMessage( "%s", logBuf );
1752 
1753     ev.Skip();
1754 }
1755 
1756 } // anonymous namespace
1757 
OnRangeSelected(wxGridRangeSelectEvent & ev)1758 void GridFrame::OnRangeSelected( wxGridRangeSelectEvent& ev )
1759 {
1760     LogRangeSelectEvent(ev, "ed");
1761 }
1762 
OnRangeSelecting(wxGridRangeSelectEvent & ev)1763 void GridFrame::OnRangeSelecting( wxGridRangeSelectEvent& ev )
1764 {
1765     LogRangeSelectEvent(ev, "ing");
1766 }
1767 
OnCellValueChanging(wxGridEvent & ev)1768 void GridFrame::OnCellValueChanging( wxGridEvent& ev )
1769 {
1770     int row = ev.GetRow(),
1771         col = ev.GetCol();
1772 
1773     wxLogMessage("Value of cell at (%d, %d): about to change "
1774                  "from \"%s\" to \"%s\"",
1775                  row, col,
1776                  grid->GetCellValue(row, col), ev.GetString());
1777 
1778     // test how vetoing works
1779     if ( ev.GetString() == "42" )
1780     {
1781         wxLogMessage("Vetoing the change.");
1782         ev.Veto();
1783         return;
1784     }
1785 
1786     ev.Skip();
1787 }
1788 
OnCellValueChanged(wxGridEvent & ev)1789 void GridFrame::OnCellValueChanged( wxGridEvent& ev )
1790 {
1791     int row = ev.GetRow(),
1792         col = ev.GetCol();
1793 
1794     wxLogMessage("Value of cell at (%d, %d) changed and is now \"%s\" "
1795                  "(was \"%s\")",
1796                  row, col,
1797                  grid->GetCellValue(row, col), ev.GetString());
1798 
1799     ev.Skip();
1800 }
1801 
OnCellBeginDrag(wxGridEvent & ev)1802 void GridFrame::OnCellBeginDrag( wxGridEvent& ev )
1803 {
1804     wxLogMessage("Got request to drag cell at row %d, col %d",
1805                  ev.GetRow(), ev.GetCol());
1806 
1807     ev.Skip();
1808 }
1809 
OnEditorShown(wxGridEvent & ev)1810 void GridFrame::OnEditorShown( wxGridEvent& ev )
1811 {
1812 
1813     if ( (ev.GetCol() == 4) &&
1814          (ev.GetRow() == 0) &&
1815      (wxMessageBox("Are you sure you wish to edit this cell",
1816                    "Checking",wxYES_NO) == wxNO ) ) {
1817 
1818      ev.Veto();
1819      return;
1820     }
1821 
1822     wxLogMessage( "Cell editor shown." );
1823 
1824     ev.Skip();
1825 }
1826 
OnEditorHidden(wxGridEvent & ev)1827 void GridFrame::OnEditorHidden( wxGridEvent& ev )
1828 {
1829 
1830     if ( (ev.GetCol() == 4) &&
1831          (ev.GetRow() == 0) &&
1832      (wxMessageBox("Are you sure you wish to finish editing this cell",
1833                    "Checking",wxYES_NO) == wxNO ) ) {
1834 
1835         ev.Veto();
1836         return;
1837     }
1838 
1839     wxLogMessage( "Cell editor hidden." );
1840 
1841     ev.Skip();
1842 }
1843 
OnAbout(wxCommandEvent & WXUNUSED (ev))1844 void GridFrame::OnAbout(  wxCommandEvent& WXUNUSED(ev) )
1845 {
1846     wxAboutDialogInfo aboutInfo;
1847     aboutInfo.SetName("wxGrid demo");
1848     aboutInfo.SetDescription(_("wxGrid sample program"));
1849     aboutInfo.AddDeveloper("Michael Bedward");
1850     aboutInfo.AddDeveloper("Julian Smart");
1851     aboutInfo.AddDeveloper("Vadim Zeitlin");
1852 
1853     // this is just to force the generic version of the about
1854     // dialog under wxMSW so that it's easy to test if the grid
1855     // repaints correctly when it has lost focus and a dialog
1856     // (different from the Windows standard message box -- it doesn't
1857     // work with it for some reason) is moved over it.
1858     aboutInfo.SetWebSite("http://www.wxwidgets.org");
1859 
1860     wxAboutBox(aboutInfo, this);
1861 }
1862 
1863 
OnClear(wxCommandEvent & WXUNUSED (ev))1864 void GridFrame::OnClear( wxCommandEvent& WXUNUSED(ev) )
1865 {
1866 #if wxUSE_LOG
1867     logWin->Clear();
1868 #endif // wxUSE_LOG
1869 }
1870 
OnQuit(wxCommandEvent & WXUNUSED (ev))1871 void GridFrame::OnQuit( wxCommandEvent& WXUNUSED(ev) )
1872 {
1873     Close( true );
1874 }
1875 
OnBugsTable(wxCommandEvent &)1876 void GridFrame::OnBugsTable(wxCommandEvent& )
1877 {
1878     BugsGridFrame *frame = new BugsGridFrame;
1879     frame->Show(true);
1880 }
1881 
1882 // ----------------------------------------------------------------------------
1883 // MyGridCellAttrProvider
1884 // ----------------------------------------------------------------------------
1885 
MyGridCellAttrProvider()1886 MyGridCellAttrProvider::MyGridCellAttrProvider()
1887     : m_attrForOddRows(new wxGridCellAttr)
1888 {
1889     m_attrForOddRows->SetBackgroundColour(*wxLIGHT_GREY);
1890 }
1891 
GetAttr(int row,int col,wxGridCellAttr::wxAttrKind kind) const1892 wxGridCellAttr *MyGridCellAttrProvider::GetAttr(int row, int col,
1893                            wxGridCellAttr::wxAttrKind  kind /* = wxGridCellAttr::Any */) const
1894 {
1895     wxGridCellAttrPtr attr(wxGridCellAttrProvider::GetAttr(row, col, kind));
1896 
1897     if ( row % 2 )
1898     {
1899         if ( !attr )
1900         {
1901             attr = m_attrForOddRows;
1902         }
1903         else
1904         {
1905             if ( !attr->HasBackgroundColour() )
1906             {
1907                 attr = attr->Clone();
1908                 attr->SetBackgroundColour(*wxLIGHT_GREY);
1909             }
1910         }
1911     }
1912 
1913     return attr.release();
1914 }
1915 
OnVTable(wxCommandEvent &)1916 void GridFrame::OnVTable(wxCommandEvent& )
1917 {
1918     static long s_sizeGrid = 10000;
1919 
1920     s_sizeGrid = wxGetNumberFromUser("Size of the table to create",
1921                                      "Size: ",
1922                                      "wxGridDemo question",
1923                                      s_sizeGrid,
1924                                      0, 32000, this);
1925 
1926     if ( s_sizeGrid != -1 )
1927     {
1928         BigGridFrame* win = new BigGridFrame(s_sizeGrid);
1929         win->Show(true);
1930     }
1931 }
1932 
1933 // ----------------------------------------------------------------------------
1934 // MyGridCellRenderer
1935 // ----------------------------------------------------------------------------
1936 
1937 // do something that the default renderer doesn't here just to show that it is
1938 // possible to alter the appearance of the cell beyond what the attributes
1939 // allow
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rect,int row,int col,bool isSelected)1940 void MyGridCellRenderer::Draw(wxGrid& grid,
1941                               wxGridCellAttr& attr,
1942                               wxDC& dc,
1943                               const wxRect& rect,
1944                               int row, int col,
1945                               bool isSelected)
1946 {
1947     wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
1948 
1949     dc.SetPen(*wxGREEN_PEN);
1950     dc.SetBrush(*wxTRANSPARENT_BRUSH);
1951     dc.DrawEllipse(rect);
1952 }
1953 
1954 // ============================================================================
1955 // BigGridFrame and BigGridTable:  Sample of a non-standard table
1956 // ============================================================================
1957 
BigGridFrame(long sizeGrid)1958 BigGridFrame::BigGridFrame(long sizeGrid)
1959             : wxFrame(NULL, wxID_ANY, "Plugin Virtual Table")
1960 {
1961     m_grid = new wxGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
1962     m_table = new BigGridTable(sizeGrid);
1963 
1964     // VZ: I don't understand why this slows down the display that much,
1965     //     must profile it...
1966     //m_table->SetAttrProvider(new MyGridCellAttrProvider);
1967 
1968     m_grid->AssignTable(m_table);
1969 
1970     SetClientSize(FromDIP(wxSize(500, 450)));
1971 }
1972 
1973 // ============================================================================
1974 // BugsGridFrame: a "realistic" table
1975 // ============================================================================
1976 
1977 // ----------------------------------------------------------------------------
1978 // bugs table data
1979 // ----------------------------------------------------------------------------
1980 
1981 enum Columns
1982 {
1983     Col_Id,
1984     Col_Summary,
1985     Col_Severity,
1986     Col_Priority,
1987     Col_Platform,
1988     Col_Opened,
1989     Col_Max
1990 };
1991 
1992 enum Severity
1993 {
1994     Sev_Wish,
1995     Sev_Minor,
1996     Sev_Normal,
1997     Sev_Major,
1998     Sev_Critical,
1999     Sev_Max
2000 };
2001 
2002 static const wxString severities[] =
2003 {
2004     "wishlist",
2005     "minor",
2006     "normal",
2007     "major",
2008     "critical",
2009 };
2010 
2011 static struct BugsGridData
2012 {
2013     int id;
2014     wxString summary;
2015     Severity severity;
2016     int prio;
2017     wxString platform;
2018     bool opened;
2019 } gs_dataBugsGrid [] =
2020 {
2021     { 18, "foo doesn't work", Sev_Major, 1, "wxMSW", true },
2022     { 27, "bar crashes", Sev_Critical, 1, "all", false },
2023     { 45, "printing is slow", Sev_Minor, 3, "wxMSW", true },
2024     { 68, "Rectangle() fails", Sev_Normal, 1, "wxMSW", false },
2025 };
2026 
2027 // ----------------------------------------------------------------------------
2028 // BugsGridTable
2029 // ----------------------------------------------------------------------------
2030 
GetTypeName(int WXUNUSED (row),int col)2031 wxString BugsGridTable::GetTypeName(int WXUNUSED(row), int col)
2032 {
2033     switch ( col )
2034     {
2035         case Col_Id:
2036         case Col_Priority:
2037             return wxGRID_VALUE_NUMBER;
2038 
2039         case Col_Severity:
2040             // fall thorugh (TODO should be a list)
2041 
2042         case Col_Summary:
2043             return wxString::Format("%s:80", wxGRID_VALUE_STRING);
2044 
2045         case Col_Platform:
2046             return wxString::Format("%s:all,MSW,GTK,other", wxGRID_VALUE_CHOICE);
2047 
2048         case Col_Opened:
2049             return wxGRID_VALUE_BOOL;
2050     }
2051 
2052     wxFAIL_MSG("unknown column");
2053 
2054     return wxEmptyString;
2055 }
2056 
GetNumberRows()2057 int BugsGridTable::GetNumberRows()
2058 {
2059     return WXSIZEOF(gs_dataBugsGrid);
2060 }
2061 
GetNumberCols()2062 int BugsGridTable::GetNumberCols()
2063 {
2064     return Col_Max;
2065 }
2066 
IsEmptyCell(int WXUNUSED (row),int WXUNUSED (col))2067 bool BugsGridTable::IsEmptyCell( int WXUNUSED(row), int WXUNUSED(col) )
2068 {
2069     return false;
2070 }
2071 
GetValue(int row,int col)2072 wxString BugsGridTable::GetValue( int row, int col )
2073 {
2074     const BugsGridData& gd = gs_dataBugsGrid[row];
2075 
2076     switch ( col )
2077     {
2078         case Col_Id:
2079             return wxString::Format("%d", gd.id);
2080 
2081         case Col_Priority:
2082             return wxString::Format("%d", gd.prio);
2083 
2084         case Col_Opened:
2085             return gd.opened ? "1" : "0";
2086 
2087         case Col_Severity:
2088             return severities[gd.severity];
2089 
2090         case Col_Summary:
2091             return gd.summary;
2092 
2093         case Col_Platform:
2094             return gd.platform;
2095     }
2096 
2097     return wxEmptyString;
2098 }
2099 
SetValue(int row,int col,const wxString & value)2100 void BugsGridTable::SetValue( int row, int col, const wxString& value )
2101 {
2102     BugsGridData& gd = gs_dataBugsGrid[row];
2103 
2104     switch ( col )
2105     {
2106         case Col_Id:
2107         case Col_Priority:
2108         case Col_Opened:
2109             wxFAIL_MSG("unexpected column");
2110             break;
2111 
2112         case Col_Severity:
2113             {
2114                 size_t n;
2115                 for ( n = 0; n < WXSIZEOF(severities); n++ )
2116                 {
2117                     if ( severities[n] == value )
2118                     {
2119                         gd.severity = (Severity)n;
2120                         break;
2121                     }
2122                 }
2123 
2124                 if ( n == WXSIZEOF(severities) )
2125                 {
2126                     wxLogWarning("Invalid severity value '%s'.",
2127                                  value);
2128                     gd.severity = Sev_Normal;
2129                 }
2130             }
2131             break;
2132 
2133         case Col_Summary:
2134             gd.summary = value;
2135             break;
2136 
2137         case Col_Platform:
2138             gd.platform = value;
2139             break;
2140     }
2141 }
2142 
2143 bool
CanGetValueAs(int WXUNUSED (row),int col,const wxString & typeName)2144 BugsGridTable::CanGetValueAs(int WXUNUSED(row),
2145                              int col,
2146                              const wxString& typeName)
2147 {
2148     if ( typeName == wxGRID_VALUE_STRING )
2149     {
2150         return true;
2151     }
2152     else if ( typeName == wxGRID_VALUE_BOOL )
2153     {
2154         return col == Col_Opened;
2155     }
2156     else if ( typeName == wxGRID_VALUE_NUMBER )
2157     {
2158         return col == Col_Id || col == Col_Priority || col == Col_Severity;
2159     }
2160     else
2161     {
2162         return false;
2163     }
2164 }
2165 
CanSetValueAs(int row,int col,const wxString & typeName)2166 bool BugsGridTable::CanSetValueAs( int row, int col, const wxString& typeName )
2167 {
2168     return CanGetValueAs(row, col, typeName);
2169 }
2170 
GetValueAsLong(int row,int col)2171 long BugsGridTable::GetValueAsLong( int row, int col )
2172 {
2173     const BugsGridData& gd = gs_dataBugsGrid[row];
2174 
2175     switch ( col )
2176     {
2177         case Col_Id:
2178             return gd.id;
2179 
2180         case Col_Priority:
2181             return gd.prio;
2182 
2183         case Col_Severity:
2184             return gd.severity;
2185 
2186         default:
2187             wxFAIL_MSG("unexpected column");
2188             return -1;
2189     }
2190 }
2191 
GetValueAsBool(int row,int col)2192 bool BugsGridTable::GetValueAsBool( int row, int col )
2193 {
2194     if ( col == Col_Opened )
2195     {
2196         return gs_dataBugsGrid[row].opened;
2197     }
2198     else
2199     {
2200         wxFAIL_MSG("unexpected column");
2201 
2202         return false;
2203     }
2204 }
2205 
SetValueAsLong(int row,int col,long value)2206 void BugsGridTable::SetValueAsLong( int row, int col, long value )
2207 {
2208     BugsGridData& gd = gs_dataBugsGrid[row];
2209 
2210     switch ( col )
2211     {
2212         case Col_Priority:
2213             gd.prio = value;
2214             break;
2215 
2216         default:
2217             wxFAIL_MSG("unexpected column");
2218     }
2219 }
2220 
SetValueAsBool(int row,int col,bool value)2221 void BugsGridTable::SetValueAsBool( int row, int col, bool value )
2222 {
2223     if ( col == Col_Opened )
2224     {
2225         gs_dataBugsGrid[row].opened = value;
2226     }
2227     else
2228     {
2229         wxFAIL_MSG("unexpected column");
2230     }
2231 }
2232 
GetColLabelValue(int col)2233 wxString BugsGridTable::GetColLabelValue( int col )
2234 {
2235     static const wxString headers[] = { "Id",
2236         "Summary",
2237         "Severity",
2238         "Priority",
2239         "Platform",
2240         "Opened?" };
2241     return headers[col];
2242 }
2243 
2244 // ----------------------------------------------------------------------------
2245 // BugsGridFrame
2246 // ----------------------------------------------------------------------------
2247 
BugsGridFrame()2248 BugsGridFrame::BugsGridFrame()
2249              : wxFrame(NULL, wxID_ANY, "Bugs table")
2250 {
2251     wxGrid *grid = new wxGrid(this, wxID_ANY);
2252     wxGridTableBase *table = new BugsGridTable();
2253     table->SetAttrProvider(new MyGridCellAttrProvider);
2254     grid->AssignTable(table);
2255 
2256     wxGridCellAttr *attrRO = new wxGridCellAttr,
2257                    *attrRangeEditor = new wxGridCellAttr,
2258                    *attrCombo = new wxGridCellAttr;
2259 
2260     attrRO->SetReadOnly();
2261     attrRangeEditor->SetEditor(new wxGridCellNumberEditor(1, 5));
2262     attrCombo->SetEditor(new wxGridCellChoiceEditor(WXSIZEOF(severities),
2263                                                     severities));
2264 
2265     grid->SetColAttr(Col_Id, attrRO);
2266     grid->SetColAttr(Col_Priority, attrRangeEditor);
2267     grid->SetColAttr(Col_Severity, attrCombo);
2268 
2269     grid->Fit();
2270     SetClientSize(grid->GetSize());
2271 }
2272 
2273 // ============================================================================
2274 // TabularGrid: grid used for display of tabular data
2275 // ============================================================================
2276 
2277 class TabularGridTable : public wxGridTableBase
2278 {
2279 public:
2280     enum
2281     {
2282         COL_NAME,
2283         COL_EXT,
2284         COL_SIZE,
2285         COL_DATE,
2286         COL_MAX
2287     };
2288 
2289     enum
2290     {
2291         ROW_MAX = 3
2292     };
2293 
TabularGridTable()2294     TabularGridTable() { m_sortOrder = NULL; }
2295 
GetNumberRows()2296     virtual int GetNumberRows() wxOVERRIDE { return ROW_MAX; }
GetNumberCols()2297     virtual int GetNumberCols() wxOVERRIDE { return COL_MAX; }
2298 
GetValue(int row,int col)2299     virtual wxString GetValue(int row, int col) wxOVERRIDE
2300     {
2301         if ( m_sortOrder )
2302             row = m_sortOrder[row];
2303 
2304         switch ( col )
2305         {
2306             case COL_NAME:
2307             case COL_EXT:
2308                 return GetNameOrExt(row, col);
2309 
2310             case COL_SIZE:
2311                 return wxString::Format("%lu", GetSize(row));
2312 
2313             case COL_DATE:
2314                 return GetDate(row).FormatDate();
2315 
2316             case COL_MAX:
2317             default:
2318                 wxFAIL_MSG( "unknown column" );
2319         }
2320 
2321         return wxString();
2322     }
2323 
SetValue(int,int,const wxString &)2324     virtual void SetValue(int, int, const wxString&) wxOVERRIDE
2325     {
2326         wxFAIL_MSG( "shouldn't be called" );
2327     }
2328 
GetColLabelValue(int col)2329     virtual wxString GetColLabelValue(int col) wxOVERRIDE
2330     {
2331         // notice that column parameter here always refers to the internal
2332         // column index, independently of its position on the screen
2333         static const char *labels[] = { "Name", "Extension", "Size", "Date" };
2334         wxCOMPILE_TIME_ASSERT( WXSIZEOF(labels) == COL_MAX, LabelsMismatch );
2335 
2336         return labels[col];
2337     }
2338 
SetColLabelValue(int,const wxString &)2339     virtual void SetColLabelValue(int, const wxString&) wxOVERRIDE
2340     {
2341         wxFAIL_MSG( "shouldn't be called" );
2342     }
2343 
Sort(int col,bool ascending)2344     void Sort(int col, bool ascending)
2345     {
2346         // we hardcode all sorting orders for simplicity here
2347         static int sortOrders[COL_MAX][2][ROW_MAX] =
2348         {
2349             // descending   ascending
2350             { { 2, 1, 0 }, { 0, 1, 2 } },
2351             { { 2, 1, 0 }, { 0, 1, 2 } },
2352             { { 2, 1, 0 }, { 0, 1, 2 } },
2353             { { 1, 0, 2 }, { 2, 0, 1 } },
2354         };
2355 
2356         m_sortOrder = col == wxNOT_FOUND ? NULL : sortOrders[col][ascending];
2357     }
2358 
2359 private:
GetNameOrExt(int row,int col) const2360     wxString GetNameOrExt(int row, int col) const
2361     {
2362         static const char *
2363             names[] = { "autoexec.bat", "boot.ini", "io.sys" };
2364         wxCOMPILE_TIME_ASSERT( WXSIZEOF(names) == ROW_MAX, NamesMismatch );
2365 
2366         const wxString s(names[row]);
2367         return col == COL_NAME ? s.BeforeFirst('.') : s.AfterLast('.');
2368     }
2369 
GetSize(int row) const2370     unsigned long GetSize(int row) const
2371     {
2372         static const unsigned long
2373             sizes[] = { 412, 604, 40774 };
2374         wxCOMPILE_TIME_ASSERT( WXSIZEOF(sizes) == ROW_MAX, SizesMismatch );
2375 
2376         return sizes[row];
2377     }
2378 
GetDate(int row) const2379     wxDateTime GetDate(int row) const
2380     {
2381         static const char *
2382             dates[] = { "2004-04-17", "2006-05-27", "1994-05-31" };
2383         wxCOMPILE_TIME_ASSERT( WXSIZEOF(dates) == ROW_MAX, DatesMismatch );
2384 
2385         wxDateTime dt;
2386         dt.ParseISODate(dates[row]);
2387         return dt;
2388     }
2389 
2390     int *m_sortOrder;
2391 };
2392 
2393 // specialized text control for column indexes entry
2394 class ColIndexEntry : public wxTextCtrl
2395 {
2396 public:
ColIndexEntry(wxWindow * parent)2397     ColIndexEntry(wxWindow *parent)
2398         : wxTextCtrl(parent, wxID_ANY, "")
2399     {
2400         SetValidator(wxTextValidator(wxFILTER_NUMERIC));
2401     }
2402 
GetCol()2403     int GetCol()
2404     {
2405         unsigned long col;
2406         if ( !GetValue().ToULong(&col) || col > TabularGridTable::COL_MAX )
2407         {
2408             SetFocus();
2409             return -1;
2410         }
2411 
2412         return col;
2413     }
2414 
2415 protected:
DoGetBestSize() const2416     virtual wxSize DoGetBestSize() const wxOVERRIDE
2417     {
2418         wxSize size = wxTextCtrl::DoGetBestSize();
2419         size.x = 3*GetCharWidth();
2420         return size;
2421     }
2422 };
2423 
2424 class TabularGridFrame : public wxFrame
2425 {
2426 public:
2427     TabularGridFrame();
2428 
2429 private:
2430     enum // control ids
2431     {
2432         Id_Check_UseNativeHeader,
2433         Id_Check_DrawNativeLabels,
2434         Id_Check_ShowRowLabels,
2435         Id_Check_EnableColMove
2436     };
2437 
2438     // event handlers
2439 
OnToggleUseNativeHeader(wxCommandEvent &)2440     void OnToggleUseNativeHeader(wxCommandEvent&)
2441     {
2442         m_grid->UseNativeColHeader(m_chkUseNative->IsChecked());
2443     }
2444 
OnUpdateDrawNativeLabelsUI(wxUpdateUIEvent & event)2445     void OnUpdateDrawNativeLabelsUI(wxUpdateUIEvent& event)
2446     {
2447         // we don't draw labels at all, native or otherwise, if we use the
2448         // native header control
2449         event.Enable( !m_chkUseNative->GetValue() );
2450     }
2451 
OnToggleDrawNativeLabels(wxCommandEvent &)2452     void OnToggleDrawNativeLabels(wxCommandEvent&)
2453     {
2454         m_grid->SetUseNativeColLabels(m_chkDrawNative->IsChecked());
2455     }
2456 
OnToggleShowRowLabels(wxCommandEvent &)2457     void OnToggleShowRowLabels(wxCommandEvent&)
2458     {
2459         m_grid->SetRowLabelSize(m_chkShowRowLabels->IsChecked()
2460                                     ? wxGRID_AUTOSIZE
2461                                     : 0);
2462     }
2463 
OnToggleColMove(wxCommandEvent &)2464     void OnToggleColMove(wxCommandEvent&)
2465     {
2466         m_grid->EnableDragColMove(m_chkEnableColMove->IsChecked());
2467     }
2468 
OnShowHideColumn(wxCommandEvent & event)2469     void OnShowHideColumn(wxCommandEvent& event)
2470     {
2471         int col = m_txtColShowHide->GetCol();
2472         if ( col != -1 )
2473         {
2474             m_grid->SetColSize(col,
2475                                event.GetId() == wxID_ADD ? wxGRID_AUTOSIZE : 0);
2476 
2477             UpdateOrderAndVisibility();
2478         }
2479     }
2480 
OnMoveColumn(wxCommandEvent &)2481     void OnMoveColumn(wxCommandEvent&)
2482     {
2483         int col = m_txtColIndex->GetCol();
2484         int pos = m_txtColPos->GetCol();
2485         if ( col == -1 || pos == -1 )
2486             return;
2487 
2488         m_grid->SetColPos(col, pos);
2489 
2490         UpdateOrderAndVisibility();
2491     }
2492 
OnResetColumnOrder(wxCommandEvent &)2493     void OnResetColumnOrder(wxCommandEvent&)
2494     {
2495         m_grid->ResetColPos();
2496 
2497         UpdateOrderAndVisibility();
2498     }
2499 
OnGridColSort(wxGridEvent & event)2500     void OnGridColSort(wxGridEvent& event)
2501     {
2502         const int col = event.GetCol();
2503         m_table->Sort(col, !(m_grid->IsSortingBy(col) &&
2504                              m_grid->IsSortOrderAscending()));
2505     }
2506 
OnGridColMove(wxGridEvent & event)2507     void OnGridColMove(wxGridEvent& event)
2508     {
2509         // can't update it yet as the order hasn't been changed, so do it a bit
2510         // later
2511         m_shouldUpdateOrder = true;
2512 
2513         event.Skip();
2514     }
2515 
OnGridColSize(wxGridSizeEvent & event)2516     void OnGridColSize(wxGridSizeEvent& event)
2517     {
2518         // we only catch this event to react to the user showing or hiding this
2519         // column using the header control menu and not because we're
2520         // interested in column resizing
2521         UpdateOrderAndVisibility();
2522 
2523         event.Skip();
2524     }
2525 
OnIdle(wxIdleEvent & event)2526     void OnIdle(wxIdleEvent& event)
2527     {
2528         if ( m_shouldUpdateOrder )
2529         {
2530             m_shouldUpdateOrder = false;
2531             UpdateOrderAndVisibility();
2532         }
2533 
2534         event.Skip();
2535     }
2536 
UpdateOrderAndVisibility()2537     void UpdateOrderAndVisibility()
2538     {
2539         wxString s;
2540         for ( int pos = 0; pos < TabularGridTable::COL_MAX; pos++ )
2541         {
2542             const int col = m_grid->GetColAt(pos);
2543             const bool isHidden = m_grid->GetColSize(col) == 0;
2544 
2545             if ( isHidden )
2546                 s << '[';
2547             s << col;
2548             if ( isHidden )
2549                 s << ']';
2550 
2551             s << ' ';
2552         }
2553 
2554         m_statOrder->SetLabel(s);
2555     }
2556 
2557     // controls
2558     wxGrid *m_grid;
2559     TabularGridTable *m_table;
2560     wxCheckBox *m_chkUseNative,
2561                *m_chkDrawNative,
2562                *m_chkShowRowLabels,
2563                *m_chkEnableColMove;
2564 
2565     ColIndexEntry *m_txtColIndex,
2566                   *m_txtColPos,
2567                   *m_txtColShowHide;
2568 
2569     wxStaticText *m_statOrder;
2570 
2571     // fla for EVT_IDLE handler
2572     bool m_shouldUpdateOrder;
2573 
2574     wxDECLARE_NO_COPY_CLASS(TabularGridFrame);
2575     wxDECLARE_EVENT_TABLE();
2576 };
2577 
wxBEGIN_EVENT_TABLE(TabularGridFrame,wxFrame)2578 wxBEGIN_EVENT_TABLE(TabularGridFrame, wxFrame)
2579     EVT_CHECKBOX(Id_Check_UseNativeHeader,
2580                  TabularGridFrame::OnToggleUseNativeHeader)
2581     EVT_CHECKBOX(Id_Check_DrawNativeLabels,
2582                  TabularGridFrame::OnToggleDrawNativeLabels)
2583     EVT_CHECKBOX(Id_Check_ShowRowLabels,
2584                  TabularGridFrame::OnToggleShowRowLabels)
2585     EVT_CHECKBOX(Id_Check_EnableColMove,
2586                  TabularGridFrame::OnToggleColMove)
2587 
2588     EVT_UPDATE_UI(Id_Check_DrawNativeLabels,
2589                   TabularGridFrame::OnUpdateDrawNativeLabelsUI)
2590 
2591     EVT_BUTTON(wxID_APPLY, TabularGridFrame::OnMoveColumn)
2592     EVT_BUTTON(wxID_RESET, TabularGridFrame::OnResetColumnOrder)
2593     EVT_BUTTON(wxID_ADD, TabularGridFrame::OnShowHideColumn)
2594     EVT_BUTTON(wxID_DELETE, TabularGridFrame::OnShowHideColumn)
2595 
2596     EVT_GRID_COL_SORT(TabularGridFrame::OnGridColSort)
2597     EVT_GRID_COL_MOVE(TabularGridFrame::OnGridColMove)
2598     EVT_GRID_COL_SIZE(TabularGridFrame::OnGridColSize)
2599 
2600     EVT_IDLE(TabularGridFrame::OnIdle)
2601 wxEND_EVENT_TABLE()
2602 
2603 TabularGridFrame::TabularGridFrame()
2604                 : wxFrame(NULL, wxID_ANY, "Tabular table")
2605 {
2606     m_shouldUpdateOrder = false;
2607 
2608     wxPanel * const panel = new wxPanel(this);
2609 
2610     // create and initialize the grid with the specified data
2611     m_table = new TabularGridTable;
2612     m_grid = new wxGrid(panel, wxID_ANY,
2613                         wxDefaultPosition, wxDefaultSize,
2614                         wxBORDER_STATIC | wxWANTS_CHARS);
2615     m_grid->AssignTable(m_table, wxGrid::wxGridSelectRows);
2616 
2617     m_grid->EnableDragColMove();
2618     m_grid->UseNativeColHeader();
2619     m_grid->HideRowLabels();
2620 
2621     // add it and the other controls to the frame
2622     wxSizer * const sizerTop = new wxBoxSizer(wxVERTICAL);
2623     sizerTop->Add(m_grid, wxSizerFlags(1).Expand().Border());
2624 
2625     wxSizer * const sizerControls = new wxBoxSizer(wxHORIZONTAL);
2626 
2627     wxSizer * const sizerStyles = new wxBoxSizer(wxVERTICAL);
2628     m_chkUseNative = new wxCheckBox(panel, Id_Check_UseNativeHeader,
2629                                     "&Use native header");
2630     m_chkUseNative->SetValue(true);
2631     sizerStyles->Add(m_chkUseNative, wxSizerFlags().Border());
2632 
2633     m_chkDrawNative = new wxCheckBox(panel, Id_Check_DrawNativeLabels,
2634                                     "&Draw native column labels");
2635     sizerStyles->Add(m_chkDrawNative, wxSizerFlags().Border());
2636 
2637     m_chkShowRowLabels = new wxCheckBox(panel, Id_Check_ShowRowLabels,
2638                                         "Show &row labels");
2639     sizerStyles->Add(m_chkShowRowLabels, wxSizerFlags().Border());
2640 
2641     m_chkEnableColMove = new wxCheckBox(panel, Id_Check_EnableColMove,
2642                                         "Allow column re&ordering");
2643     m_chkEnableColMove->SetValue(true);
2644     sizerStyles->Add(m_chkEnableColMove, wxSizerFlags().Border());
2645     sizerControls->Add(sizerStyles);
2646 
2647     sizerControls->AddSpacer(FromDIP(10));
2648 
2649     wxSizer * const sizerColumns = new wxBoxSizer(wxVERTICAL);
2650     wxSizer * const sizerMoveCols = new wxBoxSizer(wxHORIZONTAL);
2651     const wxSizerFlags
2652         flagsHorz(wxSizerFlags().Border(wxLEFT | wxRIGHT).Centre());
2653     sizerMoveCols->Add(new wxStaticText(panel, wxID_ANY, "&Move column"),
2654                        flagsHorz);
2655     m_txtColIndex = new ColIndexEntry(panel);
2656     sizerMoveCols->Add(m_txtColIndex, flagsHorz);
2657     sizerMoveCols->Add(new wxStaticText(panel, wxID_ANY, "&to"), flagsHorz);
2658     m_txtColPos = new ColIndexEntry(panel);
2659     sizerMoveCols->Add(m_txtColPos, flagsHorz);
2660     sizerMoveCols->Add(new wxButton(panel, wxID_APPLY), flagsHorz);
2661 
2662     sizerColumns->Add(sizerMoveCols, wxSizerFlags().Expand().Border(wxBOTTOM));
2663 
2664     wxSizer * const sizerShowCols = new wxBoxSizer(wxHORIZONTAL);
2665     sizerShowCols->Add(new wxStaticText(panel, wxID_ANY, "Current order:"),
2666                        flagsHorz);
2667     m_statOrder = new wxStaticText(panel, wxID_ANY, "<<< default >>>");
2668     sizerShowCols->Add(m_statOrder, flagsHorz);
2669     sizerShowCols->Add(new wxButton(panel, wxID_RESET, "&Reset order"));
2670     sizerColumns->Add(sizerShowCols, wxSizerFlags().Expand().Border(wxTOP));
2671 
2672     wxSizer * const sizerShowHide = new wxBoxSizer(wxHORIZONTAL);
2673     sizerShowHide->Add(new wxStaticText(panel, wxID_ANY, "Show/hide column:"),
2674                        flagsHorz);
2675     m_txtColShowHide = new ColIndexEntry(panel);
2676     sizerShowHide->Add(m_txtColShowHide, flagsHorz);
2677     sizerShowHide->Add(new wxButton(panel, wxID_ADD, "&Show"), flagsHorz);
2678     sizerShowHide->Add(new wxButton(panel, wxID_DELETE, "&Hide"), flagsHorz);
2679     sizerColumns->Add(sizerShowHide, wxSizerFlags().Expand().Border(wxTOP));
2680 
2681     sizerControls->Add(sizerColumns, wxSizerFlags(1).Expand().Border());
2682 
2683     sizerTop->Add(sizerControls, wxSizerFlags().Expand().Border());
2684 
2685     panel->SetSizer(sizerTop);
2686 
2687     SetClientSize(panel->GetBestSize());
2688     SetSizeHints(GetSize());
2689 
2690     Show();
2691 }
2692 
OnTabularTable(wxCommandEvent &)2693 void GridFrame::OnTabularTable(wxCommandEvent&)
2694 {
2695     new TabularGridFrame;
2696 }
2697 
2698 // Example using wxGrid::Render
2699 // Displays a preset selection or, if it exists, a selection block
2700 // Draws the selection to a wxBitmap and displays the bitmap
OnGridRender(wxCommandEvent & event)2701 void GridFrame::OnGridRender( wxCommandEvent& event )
2702 {
2703     int styleRender = 0, i;
2704     bool useLometric = false, defSize = false;
2705     double zoom = 1;
2706     wxSize sizeOffset( 0, 0 );
2707     wxPoint pointOrigin( 0, 0 );
2708 
2709     wxMenu* menu = GetMenuBar()->GetMenu( 0 );
2710     wxMenuItem* menuItem = menu->FindItem( ID_RENDER_ROW_LABEL );
2711     menu = menuItem->GetMenu();
2712 
2713     if ( menu->FindItem( ID_RENDER_ROW_LABEL )->IsChecked() )
2714         styleRender |= wxGRID_DRAW_ROWS_HEADER;
2715     if ( menu->FindItem( ID_RENDER_COL_LABEL )->IsChecked() )
2716         styleRender |= wxGRID_DRAW_COLS_HEADER;
2717     if ( menu->FindItem( ID_RENDER_GRID_LINES )->IsChecked() )
2718         styleRender |= wxGRID_DRAW_CELL_LINES;
2719     if ( menu->FindItem( ID_RENDER_GRID_BORDER )->IsChecked() )
2720         styleRender |= wxGRID_DRAW_BOX_RECT;
2721     if ( menu->FindItem( ID_RENDER_SELECT_HLIGHT )->IsChecked() )
2722         styleRender |= wxGRID_DRAW_SELECTION;
2723     if ( menu->FindItem( ID_RENDER_LOMETRIC )->IsChecked() )
2724         useLometric = true;
2725     if ( menu->FindItem( ID_RENDER_MARGIN )->IsChecked() )
2726     {
2727         pointOrigin.x += 50;
2728         pointOrigin.y += 50;
2729         sizeOffset.IncBy( 50 );
2730     }
2731     if ( menu->FindItem( ID_RENDER_ZOOM )->IsChecked() )
2732         zoom = 1.25;
2733     if ( menu->FindItem( ID_RENDER_DEFAULT_SIZE )->IsChecked() )
2734         defSize = true;
2735 
2736     // init render area coords with a default row and col selection
2737     wxGridCellCoords topLeft( 0, 0 ), bottomRight( 8, 6 );
2738     // check whether we are printing a block selection
2739     // other selection types not catered for here
2740     if ( event.GetId() == ID_RENDER_COORDS )
2741     {
2742         topLeft.SetCol( 6 );
2743         topLeft.SetRow( 4 );
2744         bottomRight.SetCol( 15 );
2745         bottomRight.SetRow( 29 );
2746     }
2747     else if ( grid->IsSelection() && grid->GetSelectionBlockTopLeft().Count() )
2748     {
2749         wxGridCellCoordsArray cells = grid->GetSelectionBlockTopLeft();
2750         if ( grid->GetSelectionBlockBottomRight().Count() )
2751         {
2752             cells.Add( grid->GetSelectionBlockBottomRight()[ 0 ] );
2753             topLeft.Set( cells[ 0 ].GetRow(),
2754                             cells[ 0 ].GetCol() );
2755             bottomRight.Set( cells[ 1 ].GetRow(),
2756                                 cells[ 1 ].GetCol() );
2757         }
2758     }
2759 
2760     // sum col widths
2761     wxSize sizeRender( 0, 0 );
2762     wxGridSizesInfo sizeinfo = grid->GetColSizes();
2763     for ( i = topLeft.GetCol(); i <= bottomRight.GetCol(); i++ )
2764     {
2765         sizeRender.x += sizeinfo.GetSize( i );
2766     }
2767 
2768     // sum row heights
2769     sizeinfo = grid->GetRowSizes();
2770     for ( i = topLeft.GetRow(); i <= bottomRight.GetRow(); i++ )
2771     {
2772         sizeRender.y += sizeinfo.GetSize( i );
2773     }
2774 
2775     if ( styleRender & wxGRID_DRAW_ROWS_HEADER )
2776         sizeRender.x += grid->GetRowLabelSize();
2777     if ( styleRender & wxGRID_DRAW_COLS_HEADER )
2778         sizeRender.y += grid->GetColLabelSize();
2779 
2780     sizeRender.x *= zoom;
2781     sizeRender.y *= zoom;
2782 
2783     // delete any existing render frame and create new one
2784     wxWindow* win = FindWindowByName( "frameRender" );
2785     if ( win )
2786         win->Destroy();
2787 
2788     // create a frame large enough for the rendered bitmap
2789     wxFrame* frame = new wxFrame( this, wxID_ANY, "Grid Render" );
2790     frame->SetClientSize( sizeRender + sizeOffset * 2 );
2791     frame->SetName( "frameRender" );
2792 
2793     wxPanel* canvas = new wxPanel( frame, wxID_ANY );
2794 
2795     // make a bitmap large enough for any top/left offset
2796     wxBitmap bmp( sizeRender + sizeOffset );
2797     wxMemoryDC memDc(bmp);
2798 
2799     // default row labels have no background colour so set background
2800     memDc.SetBackground( wxBrush( canvas->GetBackgroundColour() ) );
2801     memDc.Clear();
2802 
2803     // convert sizeRender to mapping mode units if necessary
2804     if ( useLometric )
2805     {
2806         memDc.SetMapMode( wxMM_LOMETRIC );
2807         sizeRender.x = memDc.DeviceToLogicalXRel( sizeRender.x );
2808         sizeRender.y = memDc.DeviceToLogicalYRel( sizeRender.y );
2809     }
2810 
2811     // pass wxDefaultSize if menu item is checked
2812     if ( defSize )
2813         sizeRender = wxDefaultSize;
2814 
2815     grid->Render( memDc,
2816                   pointOrigin,
2817                   sizeRender,
2818                   topLeft, bottomRight,
2819                   wxGridRenderStyle( styleRender ) );
2820 
2821     m_gridBitmap = bmp;
2822 
2823     canvas->Bind( wxEVT_PAINT, &GridFrame::OnRenderPaint, this );
2824 
2825     frame->Show();
2826 }
2827 
OnRenderPaint(wxPaintEvent & event)2828 void GridFrame::OnRenderPaint( wxPaintEvent& event )
2829 {
2830     wxPanel* canvas = ( wxPanel* )event.GetEventObject();
2831     wxPaintDC dc( canvas );
2832     canvas->PrepareDC( dc );
2833 
2834     if ( !m_gridBitmap.IsOk() )
2835         return;
2836 
2837     wxMemoryDC memDc( m_gridBitmap );
2838 
2839     dc.Blit( 0, 0,
2840              m_gridBitmap.GetWidth(),
2841              m_gridBitmap.GetHeight(),
2842              &memDc, 0, 0 );
2843 }
2844 
HideCol(wxCommandEvent & WXUNUSED (event))2845 void GridFrame::HideCol( wxCommandEvent& WXUNUSED(event) )
2846 {
2847     grid->HideCol(0);
2848 }
2849 
ShowCol(wxCommandEvent & WXUNUSED (event))2850 void GridFrame::ShowCol( wxCommandEvent& WXUNUSED(event) )
2851 {
2852     grid->ShowCol(0);
2853 }
2854 
HideRow(wxCommandEvent & WXUNUSED (event))2855 void GridFrame::HideRow( wxCommandEvent& WXUNUSED(event) )
2856 {
2857     grid->HideRow(1);
2858 }
2859 
ShowRow(wxCommandEvent & WXUNUSED (event))2860 void GridFrame::ShowRow( wxCommandEvent& WXUNUSED(event) )
2861 {
2862     grid->ShowRow(1);
2863 }
2864 
2865 namespace
2866 {
2867 
2868 // Toggle status of either checkered or coloured cells in the grid.
2869 // Note that, for shared attribute testing purposes, with checkered cells
2870 // a cell's complete attribute is destructively overwritten (except merged
2871 // cells which are skipped). While with coloured cells only the background
2872 // colour changes.
ToggleGridCells(wxGrid * grid,bool useCheckered)2873 void ToggleGridCells(wxGrid* grid, bool useCheckered)
2874 {
2875     static bool s_checkeredOn, s_colouredOn;
2876     if ( useCheckered )
2877         s_checkeredOn = !s_checkeredOn;
2878     else
2879         s_colouredOn = !s_colouredOn;
2880 
2881     wxGridCellAttrPtr attr;
2882     if ( useCheckered && s_checkeredOn )
2883     {
2884         attr = wxGridCellAttrPtr(new wxGridCellAttr);
2885         attr->SetBackgroundColour(*wxLIGHT_GREY);
2886     }
2887 
2888     wxColour bgCol = grid->GetDefaultCellBackgroundColour();
2889 
2890     for ( int row = 0; row < grid->GetNumberRows(); ++row )
2891     {
2892         for ( int col = 0; col < grid->GetNumberCols(); ++col )
2893         {
2894             if ( useCheckered && (row ^ col) & 1 )
2895                 continue;
2896 
2897             // Skip overwriting attributes of merged cells.
2898             int rows, cols;
2899             if ( useCheckered
2900                  && grid->GetCellSize(row, col, &rows, &cols)
2901                     != wxGrid::CellSpan_None )
2902             {
2903                 continue;
2904             }
2905 
2906             if ( useCheckered )
2907             {
2908                 grid->SetAttr(row, col, attr.get());
2909 
2910                 if ( s_checkeredOn )
2911                     attr->IncRef();
2912             }
2913             else
2914             {
2915                 if ( s_colouredOn )
2916                 {
2917                     const int factor = 256 / 64;
2918                     unsigned char r, g, b;
2919                     r = (127 + row * factor + col / factor) & 0xff;
2920                     g = (col * factor + row / (factor * 2)) & 0xff;
2921                     b = ((row ^ col) * factor) & 0xff;
2922 
2923                     bgCol.Set(r < 128 ? r * 2 : 255 - r * 2,
2924                               g < 128 ? g * 2 : 255 - g * 2,
2925                               b < 128 ? b * 2 : 255 - b * 2);
2926                 }
2927 
2928                 grid->SetCellBackgroundColour(row, col, bgCol);
2929             }
2930         }
2931     }
2932 
2933     grid->Refresh();
2934 }
2935 
2936 } // anoymous namespace
2937 
ToggleCheckeredCells(wxCommandEvent & WXUNUSED (event))2938 void GridFrame::ToggleCheckeredCells( wxCommandEvent& WXUNUSED(event) )
2939 {
2940     ToggleGridCells(grid, /* useCheckered = */ true);
2941 }
2942 
ToggleColouredCells(wxCommandEvent & WXUNUSED (event))2943 void GridFrame::ToggleColouredCells( wxCommandEvent& WXUNUSED(event) )
2944 {
2945     ToggleGridCells(grid, /* useCheckered = */ false);
2946 }
2947