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