X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8a3e536cd56a1867703e1cf8946a8e863c5f59ed..48889bca6f8b2504f78c0f47b32f5e95c64d915d:/samples/grid/griddemo.cpp?ds=inline diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp index 533f984b47..37d438987e 100644 --- a/samples/grid/griddemo.cpp +++ b/samples/grid/griddemo.cpp @@ -30,12 +30,19 @@ #include "wx/colordlg.h" #include "wx/fontdlg.h" #include "wx/numdlg.h" +#include "wx/aboutdlg.h" #include "wx/grid.h" +#include "wx/headerctrl.h" #include "wx/generic/gridctrl.h" +#include "wx/generic/grideditors.h" #include "griddemo.h" +#ifndef __WXMSW__ + #include "../sample.xpm" +#endif + // ---------------------------------------------------------------------------- // wxWin macros // ---------------------------------------------------------------------------- @@ -101,8 +108,7 @@ BEGIN_EVENT_TABLE( GridFrame, wxFrame ) EVT_MENU( wxID_EXIT, GridFrame::OnQuit ) EVT_MENU( ID_VTABLE, GridFrame::OnVTable) EVT_MENU( ID_BUGS_TABLE, GridFrame::OnBugsTable) - EVT_MENU( ID_SMALL_GRID, GridFrame::OnSmallGrid) - EVT_MENU( ID_TABULAR_GRID, GridFrame::OnTabularGrid) + EVT_MENU( ID_TABULAR_TABLE, GridFrame::OnTabularTable) EVT_MENU( ID_DESELECT_CELL, GridFrame::DeselectCell) EVT_MENU( ID_DESELECT_COL, GridFrame::DeselectCol) @@ -132,7 +138,8 @@ BEGIN_EVENT_TABLE( GridFrame, wxFrame ) EVT_GRID_COL_SIZE( GridFrame::OnColSize ) EVT_GRID_SELECT_CELL( GridFrame::OnSelectCell ) EVT_GRID_RANGE_SELECT( GridFrame::OnRangeSelected ) - EVT_GRID_CELL_CHANGE( GridFrame::OnCellValueChanged ) + EVT_GRID_CELL_CHANGING( GridFrame::OnCellValueChanging ) + EVT_GRID_CELL_CHANGED( GridFrame::OnCellValueChanged ) EVT_GRID_CELL_BEGIN_DRAG( GridFrame::OnCellBeginDrag ) EVT_GRID_EDITOR_SHOWN( GridFrame::OnEditorShown ) @@ -145,11 +152,12 @@ GridFrame::GridFrame() wxDefaultPosition, wxDefaultSize ) { + SetIcon(wxICON(sample)); + wxMenu *fileMenu = new wxMenu; fileMenu->Append( ID_VTABLE, _T("&Virtual table test\tCtrl-V")); fileMenu->Append( ID_BUGS_TABLE, _T("&Bugs table test\tCtrl-B")); - fileMenu->Append( ID_SMALL_GRID, _T("&Small Grid test\tCtrl-S")); - fileMenu->Append( ID_TABULAR_GRID, _T("&Tabular Grid test\tCtrl-T")); + fileMenu->Append( ID_TABULAR_TABLE, _T("&Tabular table test\tCtrl-T")); fileMenu->AppendSeparator(); fileMenu->Append( wxID_EXIT, _T("E&xit\tAlt-X") ); @@ -369,6 +377,14 @@ GridFrame::GridFrame() grid->SetCellAlignment(7, 1, wxALIGN_CENTRE, wxALIGN_CENTRE); grid->SetCellValue(7, 1, _T("Big box!")); + // create a separator-like row: it's grey and it's non-resizeable + grid->DisableRowResize(10); + grid->SetRowSize(10, 30); + attr = new wxGridCellAttr; + attr->SetBackgroundColour(*wxLIGHT_GREY); + grid->SetRowAttr(10, attr); + grid->SetCellValue(10, 0, "You can't resize this row interactively -- try it"); + // this does exactly nothing except testing that SetAttr() handles NULL // attributes and does reference counting correctly grid->SetAttr(11, 11, NULL); @@ -924,7 +940,10 @@ void GridFrame::OnCellLeftClick( wxGridEvent& ev ) void GridFrame::OnRowSize( wxGridSizeEvent& ev ) { - wxLogMessage(_T("Resized row %d"), ev.GetRowOrCol()); + const int row = ev.GetRowOrCol(); + + wxLogMessage("Resized row %d, new height = %d", + row, grid->GetRowSize(row)); ev.Skip(); } @@ -932,7 +951,10 @@ void GridFrame::OnRowSize( wxGridSizeEvent& ev ) void GridFrame::OnColSize( wxGridSizeEvent& ev ) { - wxLogMessage(_T("Resized col %d"), ev.GetRowOrCol()); + const int col = ev.GetRowOrCol(); + + wxLogMessage("Resized column %d, new width = %d", + col, grid->GetColSize(col)); ev.Skip(); } @@ -1059,13 +1081,36 @@ void GridFrame::OnRangeSelected( wxGridRangeSelectEvent& ev ) ev.Skip(); } +void GridFrame::OnCellValueChanging( wxGridEvent& ev ) +{ + int row = ev.GetRow(), + col = ev.GetCol(); + + wxLogMessage("Value of cell at (%d, %d): about to change " + "from \"%s\" to \"%s\"", + row, col, + grid->GetCellValue(row, col), ev.GetString()); + + // test how vetoing works + if ( ev.GetString() == "42" ) + { + wxLogMessage("Vetoing the change."); + ev.Veto(); + return; + } + + ev.Skip(); +} + void GridFrame::OnCellValueChanged( wxGridEvent& ev ) { int row = ev.GetRow(), col = ev.GetCol(); - wxLogMessage(_T("Value changed for cell at row %d, col %d: now \"%s\""), - row, col, grid->GetCellValue(row, col).c_str()); + wxLogMessage("Value of cell at (%d, %d) changed and is now \"%s\" " + "(was \"%s\")", + row, col, + grid->GetCellValue(row, col), ev.GetString()); ev.Skip(); } @@ -1114,10 +1159,21 @@ void GridFrame::OnEditorHidden( wxGridEvent& ev ) void GridFrame::About( wxCommandEvent& WXUNUSED(ev) ) { - (void)wxMessageBox( _T("\n\nwxGrid demo \n\n") - _T("Michael Bedward, Julian Smart, Vadim Zeitlin"), - _T("About"), - wxOK ); + wxAboutDialogInfo aboutInfo; + aboutInfo.SetName(wxT("wxGrid demo")); + aboutInfo.SetDescription(_("wxGrid sample program")); + aboutInfo.AddDeveloper(wxT("Michael Bedward")); + aboutInfo.AddDeveloper(wxT("Julian Smart")); + aboutInfo.AddDeveloper(wxT("Vadim Zeitlin")); + + // this is just to force the generic version of the about + // dialog under wxMSW so that it's easy to test if the grid + // repaints correctly when it has lost focus and a dialog + // (different from the Windows standard message box -- it doesn't + // work with it for some reason) is moved over it. + aboutInfo.SetWebSite(wxT("http://www.wxwidgets.org")); + + wxAboutBox(aboutInfo); } @@ -1132,17 +1188,6 @@ void GridFrame::OnBugsTable(wxCommandEvent& ) frame->Show(true); } -void GridFrame::OnSmallGrid(wxCommandEvent& ) -{ - wxFrame* frame = new wxFrame(NULL, wxID_ANY, _T("A Small Grid"), - wxDefaultPosition, wxSize(640, 480)); - wxPanel* panel = new wxPanel(frame, wxID_ANY); - wxGrid* grid = new wxGrid(panel, wxID_ANY, wxPoint(10,10), wxSize(400,400), - wxWANTS_CHARS | wxSIMPLE_BORDER); - grid->CreateGrid(3,3); - frame->Show(true); -} - // ---------------------------------------------------------------------------- // MyGridCellAttrProvider // ---------------------------------------------------------------------------- @@ -1185,44 +1230,15 @@ wxGridCellAttr *MyGridCellAttrProvider::GetAttr(int row, int col, return attr; } -// ---------------------------------------------------------------------------- - -void GridFrame::OnTabularGrid(wxCommandEvent& ) -{ - wxFrame* frame = new wxFrame(NULL, wxID_ANY, _T("A small tabular Grid"), - wxDefaultPosition, wxSize(640, 480)); - wxGrid* grid = new wxGrid(frame, wxID_ANY, wxPoint(10,10), wxSize(40,40), - wxWANTS_CHARS | wxBORDER_SUNKEN); - grid->SetRowLabelSize( 0 ); - grid->DisableDragRowSize(); - grid->SetUseNativeColLabels(); - grid->CreateGrid(10,10); - grid->SetSelectionMode( wxGrid::wxGridSelectRows ); - - frame->Show(true); -} - void GridFrame::OnVTable(wxCommandEvent& ) { static long s_sizeGrid = 10000; -#ifdef __WXMOTIF__ - // MB: wxGetNumberFromUser doesn't work properly for wxMotif - wxString s; - s << s_sizeGrid; - s = wxGetTextFromUser( _T("Size of the table to create"), - _T("Size:"), - s ); - - s.ToLong( &s_sizeGrid ); - -#else s_sizeGrid = wxGetNumberFromUser(_T("Size of the table to create"), _T("Size: "), _T("wxGridDemo question"), s_sizeGrid, 0, 32000, this); -#endif if ( s_sizeGrid != -1 ) { @@ -1559,7 +1575,7 @@ wxString BugsGridTable::GetColLabelValue( int col ) BugsGridFrame::BugsGridFrame() : wxFrame(NULL, wxID_ANY, _T("Bugs table")) { - wxGrid *grid = new wxGrid(this, wxID_ANY, wxDefaultPosition); + wxGrid *grid = new wxGrid(this, wxID_ANY); wxGridTableBase *table = new BugsGridTable(); table->SetAttrProvider(new MyGridCellAttrProvider); grid->SetTable(table, true); @@ -1581,4 +1597,427 @@ BugsGridFrame::BugsGridFrame() SetClientSize(grid->GetSize()); } +// ============================================================================ +// TabularGrid: grid used for display of tabular data +// ============================================================================ + +class TabularGridTable : public wxGridTableBase +{ +public: + enum + { + COL_NAME, + COL_EXT, + COL_SIZE, + COL_DATE, + COL_MAX + }; + + enum + { + ROW_MAX = 3 + }; + + TabularGridTable() { m_sortOrder = NULL; } + + virtual int GetNumberRows() { return ROW_MAX; } + virtual int GetNumberCols() { return COL_MAX; } + + virtual wxString GetValue(int row, int col) + { + if ( m_sortOrder ) + row = m_sortOrder[row]; + + switch ( col ) + { + case COL_NAME: + case COL_EXT: + return GetNameOrExt(row, col); + + case COL_SIZE: + return wxString::Format("%lu", GetSize(row)); + + case COL_DATE: + return GetDate(row).FormatDate(); + + case COL_MAX: + default: + wxFAIL_MSG( "unknown column" ); + } + + return wxString(); + } + + virtual void SetValue(int, int, const wxString&) + { + wxFAIL_MSG( "shouldn't be called" ); + } + + virtual wxString GetColLabelValue(int col) + { + // notice that column parameter here always refers to the internal + // column index, independently of its position on the screen + static const char *labels[] = { "Name", "Extension", "Size", "Date" }; + wxCOMPILE_TIME_ASSERT( WXSIZEOF(labels) == COL_MAX, LabelsMismatch ); + + return labels[col]; + } + + virtual void SetColLabelValue(int, const wxString&) + { + wxFAIL_MSG( "shouldn't be called" ); + } + + void Sort(int col, bool ascending) + { + // we hardcode all sorting orders for simplicity here + static int sortOrders[COL_MAX][2][ROW_MAX] = + { + // descending ascending + { { 2, 1, 0 }, { 0, 1, 2 } }, + { { 2, 1, 0 }, { 0, 1, 2 } }, + { { 2, 1, 0 }, { 0, 1, 2 } }, + { { 1, 0, 2 }, { 2, 0, 1 } }, + }; + + m_sortOrder = col == wxNOT_FOUND ? NULL : sortOrders[col][ascending]; + } + +private: + wxString GetNameOrExt(int row, int col) const + { + static const char * + names[] = { "autoexec.bat", "boot.ini", "io.sys" }; + wxCOMPILE_TIME_ASSERT( WXSIZEOF(names) == ROW_MAX, NamesMismatch ); + + const wxString s(names[row]); + return col == COL_NAME ? s.BeforeFirst('.') : s.AfterLast('.'); + } + + unsigned long GetSize(int row) const + { + static const unsigned long + sizes[] = { 412, 604, 40774 }; + wxCOMPILE_TIME_ASSERT( WXSIZEOF(sizes) == ROW_MAX, SizesMismatch ); + + return sizes[row]; + } + + wxDateTime GetDate(int row) const + { + static const char * + dates[] = { "2004-04-17", "2006-05-27", "1994-05-31" }; + wxCOMPILE_TIME_ASSERT( WXSIZEOF(dates) == ROW_MAX, DatesMismatch ); + + wxDateTime dt; + dt.ParseISODate(dates[row]); + return dt; + } + + int *m_sortOrder; +}; + +// specialized text control for column indexes entry +class ColIndexEntry : public wxTextCtrl +{ +public: + ColIndexEntry(wxWindow *parent) + : wxTextCtrl(parent, wxID_ANY, "") + { + SetValidator(wxTextValidator(wxFILTER_NUMERIC)); + } + + int GetCol() + { + unsigned long col; + if ( !GetValue().ToULong(&col) || col > TabularGridTable::COL_MAX ) + { + SetFocus(); + return -1; + } + + return col; + } + +protected: + virtual wxSize DoGetBestSize() const + { + wxSize size = wxTextCtrl::DoGetBestSize(); + size.x = 3*GetCharWidth(); + return size; + } +}; + +class TabularGridFrame : public wxFrame +{ +public: + TabularGridFrame(); + +private: + enum // control ids + { + Id_Check_UseNativeHeader, + Id_Check_DrawNativeLabels, + Id_Check_ShowRowLabels, + Id_Check_EnableColMove + }; + + // event handlers + + void OnToggleUseNativeHeader(wxCommandEvent&) + { + m_grid->UseNativeColHeader(m_chkUseNative->IsChecked()); + } + + void OnUpdateDrawNativeLabelsUI(wxUpdateUIEvent& event) + { + // we don't draw labels at all, native or otherwise, if we use the + // native header control + event.Enable( !m_chkUseNative->GetValue() ); + } + + void OnToggleDrawNativeLabels(wxCommandEvent&) + { + m_grid->SetUseNativeColLabels(m_chkDrawNative->IsChecked()); + } + + void OnToggleShowRowLabels(wxCommandEvent&) + { + m_grid->SetRowLabelSize(m_chkShowRowLabels->IsChecked() + ? wxGRID_AUTOSIZE + : 0); + } + + void OnToggleColMove(wxCommandEvent&) + { + m_grid->EnableDragColMove(m_chkEnableColMove->IsChecked()); + } + + void OnShowHideColumn(wxCommandEvent& event) + { + int col = m_txtColShowHide->GetCol(); + if ( col != -1 ) + { + m_grid->SetColSize(col, + event.GetId() == wxID_ADD ? wxGRID_AUTOSIZE : 0); + + UpdateOrderAndVisibility(); + } + } + + void OnMoveColumn(wxCommandEvent&) + { + int col = m_txtColIndex->GetCol(); + int pos = m_txtColPos->GetCol(); + if ( col == -1 || pos == -1 ) + return; + + m_grid->SetColPos(col, pos); + + UpdateOrderAndVisibility(); + } + + void OnResetColumnOrder(wxCommandEvent&) + { + m_grid->ResetColPos(); + + UpdateOrderAndVisibility(); + } + + void OnGridColSort(wxGridEvent& event) + { + const int col = event.GetCol(); + m_table->Sort(col, !(m_grid->IsSortingBy(col) && + m_grid->IsSortOrderAscending())); + } + + void OnGridColMove(wxGridEvent& event) + { + // can't update it yet as the order hasn't been changed, so do it a bit + // later + m_shouldUpdateOrder = true; + + event.Skip(); + } + + void OnGridColSize(wxGridSizeEvent& event) + { + // we only catch this event to react to the user showing or hiding this + // column using the header control menu and not because we're + // interested in column resizing + UpdateOrderAndVisibility(); + event.Skip(); + } + + void OnIdle(wxIdleEvent& event) + { + if ( m_shouldUpdateOrder ) + { + m_shouldUpdateOrder = false; + UpdateOrderAndVisibility(); + } + + event.Skip(); + } + + void UpdateOrderAndVisibility() + { + wxString s; + for ( int pos = 0; pos < TabularGridTable::COL_MAX; pos++ ) + { + const int col = m_grid->GetColAt(pos); + const bool isHidden = m_grid->GetColSize(col) == 0; + + if ( isHidden ) + s << '['; + s << col; + if ( isHidden ) + s << ']'; + + s << ' '; + } + + m_statOrder->SetLabel(s); + } + + // controls + wxGrid *m_grid; + TabularGridTable *m_table; + wxCheckBox *m_chkUseNative, + *m_chkDrawNative, + *m_chkShowRowLabels, + *m_chkEnableColMove; + + ColIndexEntry *m_txtColIndex, + *m_txtColPos, + *m_txtColShowHide; + + wxStaticText *m_statOrder; + + // fla for EVT_IDLE handler + bool m_shouldUpdateOrder; + + wxDECLARE_NO_COPY_CLASS(TabularGridFrame); + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(TabularGridFrame, wxFrame) + EVT_CHECKBOX(Id_Check_UseNativeHeader, + TabularGridFrame::OnToggleUseNativeHeader) + EVT_CHECKBOX(Id_Check_DrawNativeLabels, + TabularGridFrame::OnToggleDrawNativeLabels) + EVT_CHECKBOX(Id_Check_ShowRowLabels, + TabularGridFrame::OnToggleShowRowLabels) + EVT_CHECKBOX(Id_Check_EnableColMove, + TabularGridFrame::OnToggleColMove) + + EVT_UPDATE_UI(Id_Check_DrawNativeLabels, + TabularGridFrame::OnUpdateDrawNativeLabelsUI) + + EVT_BUTTON(wxID_APPLY, TabularGridFrame::OnMoveColumn) + EVT_BUTTON(wxID_RESET, TabularGridFrame::OnResetColumnOrder) + EVT_BUTTON(wxID_ADD, TabularGridFrame::OnShowHideColumn) + EVT_BUTTON(wxID_DELETE, TabularGridFrame::OnShowHideColumn) + + EVT_GRID_COL_SORT(TabularGridFrame::OnGridColSort) + EVT_GRID_COL_MOVE(TabularGridFrame::OnGridColMove) + EVT_GRID_COL_SIZE(TabularGridFrame::OnGridColSize) + + EVT_IDLE(TabularGridFrame::OnIdle) +END_EVENT_TABLE() + +TabularGridFrame::TabularGridFrame() + : wxFrame(NULL, wxID_ANY, "Tabular table") +{ + m_shouldUpdateOrder = false; + + wxPanel * const panel = new wxPanel(this); + + // create and initialize the grid with the specified data + m_table = new TabularGridTable; + m_grid = new wxGrid(panel, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxBORDER_STATIC | wxWANTS_CHARS); + m_grid->SetTable(m_table, true, wxGrid::wxGridSelectRows); + + m_grid->EnableDragColMove(); + m_grid->UseNativeColHeader(); + m_grid->HideRowLabels(); + + // add it and the other controls to the frame + wxSizer * const sizerTop = new wxBoxSizer(wxVERTICAL); + sizerTop->Add(m_grid, wxSizerFlags(1).Expand().Border()); + + wxSizer * const sizerControls = new wxBoxSizer(wxHORIZONTAL); + + wxSizer * const sizerStyles = new wxBoxSizer(wxVERTICAL); + m_chkUseNative = new wxCheckBox(panel, Id_Check_UseNativeHeader, + "&Use native header"); + m_chkUseNative->SetValue(true); + sizerStyles->Add(m_chkUseNative, wxSizerFlags().Border()); + + m_chkDrawNative = new wxCheckBox(panel, Id_Check_DrawNativeLabels, + "&Draw native column labels"); + sizerStyles->Add(m_chkDrawNative, wxSizerFlags().Border()); + + m_chkShowRowLabels = new wxCheckBox(panel, Id_Check_ShowRowLabels, + "Show &row labels"); + sizerStyles->Add(m_chkShowRowLabels, wxSizerFlags().Border()); + + m_chkEnableColMove = new wxCheckBox(panel, Id_Check_EnableColMove, + "Allow column re&ordering"); + m_chkEnableColMove->SetValue(true); + sizerStyles->Add(m_chkEnableColMove, wxSizerFlags().Border()); + sizerControls->Add(sizerStyles); + + sizerControls->AddSpacer(10); + + wxSizer * const sizerColumns = new wxBoxSizer(wxVERTICAL); + wxSizer * const sizerMoveCols = new wxBoxSizer(wxHORIZONTAL); + const wxSizerFlags + flagsHorz(wxSizerFlags().Border(wxLEFT | wxRIGHT).Centre()); + sizerMoveCols->Add(new wxStaticText(panel, wxID_ANY, "&Move column"), + flagsHorz); + m_txtColIndex = new ColIndexEntry(panel); + sizerMoveCols->Add(m_txtColIndex, flagsHorz); + sizerMoveCols->Add(new wxStaticText(panel, wxID_ANY, "&to"), flagsHorz); + m_txtColPos = new ColIndexEntry(panel); + sizerMoveCols->Add(m_txtColPos, flagsHorz); + sizerMoveCols->Add(new wxButton(panel, wxID_APPLY), flagsHorz); + + sizerColumns->Add(sizerMoveCols, wxSizerFlags().Expand().Border(wxBOTTOM)); + + wxSizer * const sizerShowCols = new wxBoxSizer(wxHORIZONTAL); + sizerShowCols->Add(new wxStaticText(panel, wxID_ANY, "Current order:"), + flagsHorz); + m_statOrder = new wxStaticText(panel, wxID_ANY, "<<< default >>>"); + sizerShowCols->Add(m_statOrder, flagsHorz); + sizerShowCols->Add(new wxButton(panel, wxID_RESET, "&Reset order")); + sizerColumns->Add(sizerShowCols, wxSizerFlags().Expand().Border(wxTOP)); + + wxSizer * const sizerShowHide = new wxBoxSizer(wxHORIZONTAL); + sizerShowHide->Add(new wxStaticText(panel, wxID_ANY, "Show/hide column:"), + flagsHorz); + m_txtColShowHide = new ColIndexEntry(panel); + sizerShowHide->Add(m_txtColShowHide, flagsHorz); + sizerShowHide->Add(new wxButton(panel, wxID_ADD, "&Show"), flagsHorz); + sizerShowHide->Add(new wxButton(panel, wxID_DELETE, "&Hide"), flagsHorz); + sizerColumns->Add(sizerShowHide, wxSizerFlags().Expand().Border(wxTOP)); + + sizerControls->Add(sizerColumns, wxSizerFlags(1).Expand().Border()); + + sizerTop->Add(sizerControls, wxSizerFlags().Expand().Border()); + + panel->SetSizer(sizerTop); + + SetClientSize(panel->GetBestSize()); + SetSizeHints(GetSize()); + + Show(); +} + +void GridFrame::OnTabularTable(wxCommandEvent&) +{ + new TabularGridFrame; +}