From 1d8d3cc5a1ae14397d1549bd5ad6323e47b3a696 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 28 Nov 2011 13:23:33 +0000 Subject: [PATCH] Add support for custom numeric formats to wxGrid. Allow %e and %g formats (as well as their upper-letter equivalents) in addition to the default %f format for number display in wxGrid. Closes #13583. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69856 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/generic/gridctrl.h | 10 ++- include/wx/generic/grideditors.h | 37 ++++++++- interface/wx/grid.h | 64 +++++++++++++++- samples/grid/griddemo.cpp | 37 +++++---- src/generic/gridctrl.cpp | 65 ++++++++++++++-- src/generic/grideditors.cpp | 125 +++++++++++++++++++++++-------- 7 files changed, 280 insertions(+), 59 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 2f07b5e0c4..f3d6a10c09 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -477,6 +477,7 @@ All (GUI): - Allow setting window shape to arbitrary wxGraphicsPath. - Added wxTextEntry::AutoCompleteDirectories(). - Support float, double and file name values in wxGenericValidator (troelsk). +- Add support for custom numeric formats to wxGrid (Kinaou Hervé). - Fix keyboard navigation in wxGrid with hidden columns (ivan_14_32). - Add wxDataViewEvent::IsEditCancelled() (Allonii). - Send EVT_DATAVIEW_ITEM_CONTEXT_MENU events even when not clicking on an item. diff --git a/include/wx/generic/gridctrl.h b/include/wx/generic/gridctrl.h index 3ff43281fa..b9ee0a1a0f 100644 --- a/include/wx/generic/gridctrl.h +++ b/include/wx/generic/gridctrl.h @@ -81,13 +81,17 @@ protected: class WXDLLIMPEXP_ADV wxGridCellFloatRenderer : public wxGridCellStringRenderer { public: - wxGridCellFloatRenderer(int width = -1, int precision = -1); + wxGridCellFloatRenderer(int width = -1, + int precision = -1, + int format = wxGRID_FLOAT_FORMAT_DEFAULT); // get/change formatting parameters int GetWidth() const { return m_width; } void SetWidth(int width) { m_width = width; m_format.clear(); } int GetPrecision() const { return m_precision; } void SetPrecision(int precision) { m_precision = precision; m_format.clear(); } + int GetFormat() const { return m_style; } + void SetFormat(int format) { m_style = format; m_format.clear(); } // draw the string right aligned with given width/precision virtual void Draw(wxGrid& grid, @@ -102,7 +106,8 @@ public: wxDC& dc, int row, int col); - // parameters string format is "width[,precision]" + // parameters string format is "width[,precision[,format]]" + // with format being one of f|e|g|E|F|G virtual void SetParameters(const wxString& params); virtual wxGridCellRenderer *Clone() const; @@ -115,6 +120,7 @@ private: int m_width, m_precision; + int m_style; wxString m_format; }; diff --git a/include/wx/generic/grideditors.h b/include/wx/generic/grideditors.h index a81b17c9d9..e76e619576 100644 --- a/include/wx/generic/grideditors.h +++ b/include/wx/generic/grideditors.h @@ -154,11 +154,38 @@ private: wxDECLARE_NO_COPY_CLASS(wxGridCellNumberEditor); }; + +enum wxGridCellFloatFormat +{ + // Decimal floating point (%f) + wxGRID_FLOAT_FORMAT_FIXED = 0x0010, + + // Scientific notation (mantise/exponent) using e character (%e) + wxGRID_FLOAT_FORMAT_SCIENTIFIC = 0x0020, + + // Use the shorter of %e or %f (%g) + wxGRID_FLOAT_FORMAT_COMPACT = 0x0040, + + // To use in combination with one of the above formats (%F/%E/%G) + wxGRID_FLOAT_FORMAT_UPPER = 0x0080, + + // Format used by default. + wxGRID_FLOAT_FORMAT_DEFAULT = wxGRID_FLOAT_FORMAT_FIXED, + + // A mask to extract format from the combination of flags. + wxGRID_FLOAT_FORMAT_MASK = wxGRID_FLOAT_FORMAT_FIXED | + wxGRID_FLOAT_FORMAT_SCIENTIFIC | + wxGRID_FLOAT_FORMAT_COMPACT | + wxGRID_FLOAT_FORMAT_UPPER +}; + // the editor for floating point numbers (double) data class WXDLLIMPEXP_ADV wxGridCellFloatEditor : public wxGridCellTextEditor { public: - wxGridCellFloatEditor(int width = -1, int precision = -1); + wxGridCellFloatEditor(int width = -1, + int precision = -1, + int format = wxGRID_FLOAT_FORMAT_DEFAULT); virtual void Create(wxWindow* parent, wxWindowID id, @@ -176,18 +203,22 @@ public: virtual wxGridCellEditor *Clone() const { return new wxGridCellFloatEditor(m_width, m_precision); } - // parameters string format is "width,precision" + // parameters string format is "width[,precision[,format]]" + // format to choose beween f|e|g|E|G (f is used by default) virtual void SetParameters(const wxString& params); protected: // string representation of our value - wxString GetString() const; + wxString GetString(); private: int m_width, m_precision; double m_value; + int m_style; + wxString m_format; + wxDECLARE_NO_COPY_CLASS(wxGridCellFloatEditor); }; diff --git a/interface/wx/grid.h b/interface/wx/grid.h index 332011b2a5..e7b9e566ef 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -178,6 +178,31 @@ public: virtual void SetParameters(const wxString& params); }; +/** + Specifier used to format the data to string for the numbers handled by + wxGridCellFloatRenderer and wxGridCellFloatEditor. + + @since 2.9.3 +*/ +enum wxGridCellFloatFormat +{ + /// Decimal floating point (%f). + wxGRID_FLOAT_FORMAT_FIXED = 0x0010, + + /// Scientific notation (mantise/exponent) using e character (%e). + wxGRID_FLOAT_FORMAT_SCIENTIFIC = 0x0020, + + /// Use the shorter of %e or %f (%g). + wxGRID_FLOAT_FORMAT_COMPACT = 0x0040, + + /// To use in combination with one of the above formats for the upper + /// case version (%F/%E/%G) + wxGRID_FLOAT_FORMAT_UPPER = 0x0080, + + /// The format used by default (wxGRID_FLOAT_FORMAT_FIXED). + wxGRID_FLOAT_FORMAT_DEFAULT = wxGRID_FLOAT_FORMAT_FIXED +}; + /** @class wxGridCellFloatRenderer @@ -201,8 +226,22 @@ public: Minimum number of characters to be shown. @param precision Number of digits after the decimal dot. + @param format + The format used to display the string, must be a combination of + wxGridCellFloatFormat enum elements. This parameter is only + available since wxWidgets 2.9.3. */ - wxGridCellFloatRenderer(int width = -1, int precision = -1); + wxGridCellFloatRenderer(int width = -1, int precision = -1, + int format = wxGRID_FLOAT_FORMAT_DEFAULT); + + /** + Returns the specifier used to format the data to string. + + The returned value is a combination of wxGridCellFloatFormat elements. + + @since 2.9.3 + */ + int GetFormat() const; /** Returns the precision. @@ -215,7 +254,18 @@ public: int GetWidth() const; /** - Parameters string format is "width[,precision]". + Set the format to use for display the number. + + @param format + Must be a combination of wxGridCellFloatFormat enum elements. + + @since 2.9.3 + */ + void SetFormat(int format); + + /** + The parameters string format is "width[,precision[,format]]" where + @c format should be choosen beween f|e|g|E|G (f is used by default) */ virtual void SetParameters(const wxString& params); @@ -596,11 +646,17 @@ public: Minimum number of characters to be shown. @param precision Number of digits after the decimal dot. + @param format + The format to use for displaying the number, a combination of + wxGridCellFloatFormat enum elements. This parameter is only + available since wxWidgets 2.9.3. */ - wxGridCellFloatEditor(int width = -1, int precision = -1); + wxGridCellFloatEditor(int width = -1, int precision = -1, + int format = wxGRID_FLOAT_FORMAT_DEFAULT); /** - Parameters string format is "width,precision" + The parameters string format is "width[,precision[,format]]" where + @c format should be choosen beween f|e|g|E|G (f is used by default) */ virtual void SetParameters(const wxString& params); }; diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp index 93b1d95155..aa3b4d59c4 100644 --- a/samples/grid/griddemo.cpp +++ b/samples/grid/griddemo.cpp @@ -439,22 +439,33 @@ GridFrame::GridFrame() grid->SetCellValue(5, 8, wxT("Bg from row attr\nText col from cell attr")); grid->SetCellValue(5, 5, wxT("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")); + // Some numeric columns with different formatting. grid->SetColFormatFloat(6); - grid->SetCellValue(0, 6, wxString::Format(wxT("%g"), 3.1415)); - grid->SetCellValue(1, 6, wxString::Format(wxT("%g"), 1415.0)); - grid->SetCellValue(2, 6, wxString::Format(wxT("%g"), 12345.67890)); + grid->SetCellValue(0, 6, "Default\nfloat format"); + grid->SetCellValue(1, 6, wxString::Format(wxT("%g"), 3.1415)); + grid->SetCellValue(2, 6, wxString::Format(wxT("%g"), 1415.0)); + grid->SetCellValue(3, 6, wxString::Format(wxT("%g"), 12345.67890)); grid->SetColFormatFloat(7, 6, 2); - grid->SetCellValue(0, 7, wxString::Format(wxT("%g"), 3.1415)); - grid->SetCellValue(1, 7, wxString::Format(wxT("%g"), 1415.0)); - grid->SetCellValue(2, 7, wxString::Format(wxT("%g"), 12345.67890)); - - grid->SetColFormatNumber(8); - grid->SetCellValue(0, 8, "17"); - grid->SetCellValue(1, 8, "0"); - grid->SetCellValue(2, 8, "-666"); - grid->SetCellAlignment(2, 8, wxALIGN_CENTRE, wxALIGN_TOP); - grid->SetCellValue(2, 9, "<- This numeric cell should be centred"); + grid->SetCellValue(0, 7, "Width 6\nprecision 2"); + grid->SetCellValue(1, 7, wxString::Format(wxT("%g"), 3.1415)); + grid->SetCellValue(2, 7, wxString::Format(wxT("%g"), 1415.0)); + grid->SetCellValue(3, 7, wxString::Format(wxT("%g"), 12345.67890)); + + grid->SetColFormatCustom(8, + wxString::Format("%s:%i,%i,%s", wxGRID_VALUE_FLOAT, -1, 4, "g")); + grid->SetCellValue(0, 8, "Compact\nformat"); + grid->SetCellValue(1, 8, wxT("31415e-4")); + grid->SetCellValue(2, 8, wxT("1415")); + grid->SetCellValue(3, 8, wxT("123456789e-4")); + + grid->SetColFormatNumber(9); + grid->SetCellValue(0, 9, "Integer\ncolumn"); + grid->SetCellValue(1, 9, "17"); + grid->SetCellValue(2, 9, "0"); + grid->SetCellValue(3, 9, "-666"); + grid->SetCellAlignment(3, 9, wxALIGN_CENTRE, wxALIGN_TOP); + grid->SetCellValue(3, 10, "<- This numeric cell should be centred"); const wxString choices[] = { diff --git a/src/generic/gridctrl.cpp b/src/generic/gridctrl.cpp index ff201c0189..65b7edd192 100644 --- a/src/generic/gridctrl.cpp +++ b/src/generic/gridctrl.cpp @@ -598,10 +598,13 @@ wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid, // wxGridCellFloatRenderer // ---------------------------------------------------------------------------- -wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision) +wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, + int precision, + int format) { SetWidth(width); SetPrecision(precision); + SetFormat(format); } wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const @@ -609,6 +612,7 @@ wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer; renderer->m_width = m_width; renderer->m_precision = m_precision; + renderer->m_style = m_style; renderer->m_format = m_format; return renderer; @@ -641,22 +645,30 @@ wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col if ( m_precision == -1 ) { // default width/precision - m_format = wxT("%f"); + m_format = wxT("%"); } else { - m_format.Printf(wxT("%%.%df"), m_precision); + m_format.Printf(wxT("%%.%d"), m_precision); } } else if ( m_precision == -1 ) { // default precision - m_format.Printf(wxT("%%%d.f"), m_width); + m_format.Printf(wxT("%%%d."), m_width); } else { - m_format.Printf(wxT("%%%d.%df"), m_width, m_precision); + m_format.Printf(wxT("%%%d.%d"), m_width, m_precision); } + + bool isUpper = ( ( m_style & wxGRID_FLOAT_FORMAT_UPPER ) == wxGRID_FLOAT_FORMAT_UPPER); + if ( ( m_style & wxGRID_FLOAT_FORMAT_SCIENTIFIC ) == wxGRID_FLOAT_FORMAT_SCIENTIFIC) + m_format += isUpper ? wxT('E') : wxT('e'); + else if ( ( m_style & wxGRID_FLOAT_FORMAT_COMPACT ) == wxGRID_FLOAT_FORMAT_COMPACT) + m_format += isUpper ? wxT('G') : wxT('g'); + else + m_format += wxT('f'); } text.Printf(m_format, val); @@ -704,10 +716,12 @@ void wxGridCellFloatRenderer::SetParameters(const wxString& params) // reset to defaults SetWidth(-1); SetPrecision(-1); + SetFormat(wxGRID_FLOAT_FORMAT_DEFAULT); } else { - wxString tmp = params.BeforeFirst(wxT(',')); + wxString rest; + wxString tmp = params.BeforeFirst(wxT(','), &rest); if ( !tmp.empty() ) { long width; @@ -721,7 +735,7 @@ void wxGridCellFloatRenderer::SetParameters(const wxString& params) } } - tmp = params.AfterFirst(wxT(',')); + tmp = rest.BeforeFirst(wxT(',')); if ( !tmp.empty() ) { long precision; @@ -734,6 +748,43 @@ void wxGridCellFloatRenderer::SetParameters(const wxString& params) wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str()); } } + + tmp = rest.AfterFirst(wxT(',')); + if ( !tmp.empty() ) + { + if ( tmp[0] == wxT('f') ) + { + SetFormat(wxGRID_FLOAT_FORMAT_FIXED); + } + else if ( tmp[0] == wxT('e') ) + { + SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC); + } + else if ( tmp[0] == wxT('g') ) + { + SetFormat(wxGRID_FLOAT_FORMAT_COMPACT); + } + else if ( tmp[0] == wxT('E') ) + { + SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC | + wxGRID_FLOAT_FORMAT_UPPER); + } + else if ( tmp[0] == wxT('F') ) + { + SetFormat(wxGRID_FLOAT_FORMAT_FIXED | + wxGRID_FLOAT_FORMAT_UPPER); + } + else if ( tmp[0] == wxT('G') ) + { + SetFormat(wxGRID_FLOAT_FORMAT_COMPACT | + wxGRID_FLOAT_FORMAT_UPPER); + } + else + { + wxLogDebug("Invalid wxGridCellFloatRenderer format " + "parameter string '%s ignored", params); + } + } } } diff --git a/src/generic/grideditors.cpp b/src/generic/grideditors.cpp index ac90aa3310..d3113c6867 100644 --- a/src/generic/grideditors.cpp +++ b/src/generic/grideditors.cpp @@ -862,10 +862,13 @@ wxString wxGridCellNumberEditor::GetValue() const // wxGridCellFloatEditor // ---------------------------------------------------------------------------- -wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision) +wxGridCellFloatEditor::wxGridCellFloatEditor(int width, + int precision, + int format) { m_width = width; m_precision = precision; + m_style = format; } void wxGridCellFloatEditor::Create(wxWindow* parent, @@ -988,51 +991,113 @@ void wxGridCellFloatEditor::SetParameters(const wxString& params) // reset to default m_width = m_precision = -1; + m_style = wxGRID_FLOAT_FORMAT_DEFAULT; + m_format.clear(); } else { - long tmp; - if ( params.BeforeFirst(wxT(',')).ToLong(&tmp) ) + wxString rest; + wxString tmp = params.BeforeFirst(wxT(','), &rest); + if ( !tmp.empty() ) { - m_width = (int)tmp; - - if ( params.AfterFirst(wxT(',')).ToLong(&tmp) ) + long width; + if ( tmp.ToLong(&width) ) + { + m_width = (int)width; + } + else { - m_precision = (int)tmp; + wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str()); + } + } - // skip the error message below - return; + tmp = rest.BeforeFirst(wxT(',')); + if ( !tmp.empty() ) + { + long precision; + if ( tmp.ToLong(&precision) ) + { + m_precision = (int)precision; + } + else + { + wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str()); } } - wxLogDebug(wxT("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str()); + tmp = rest.AfterFirst(wxT(',')); + if ( !tmp.empty() ) + { + if ( tmp[0] == wxT('f') ) + { + m_style = wxGRID_FLOAT_FORMAT_FIXED; + } + else if ( tmp[0] == wxT('e') ) + { + m_style = wxGRID_FLOAT_FORMAT_SCIENTIFIC; + } + else if ( tmp[0] == wxT('g') ) + { + m_style = wxGRID_FLOAT_FORMAT_COMPACT; + } + else if ( tmp[0] == wxT('E') ) + { + m_style = wxGRID_FLOAT_FORMAT_SCIENTIFIC | + wxGRID_FLOAT_FORMAT_UPPER; + } + else if ( tmp[0] == wxT('F') ) + { + m_style = wxGRID_FLOAT_FORMAT_FIXED | + wxGRID_FLOAT_FORMAT_UPPER; + } + else if ( tmp[0] == wxT('G') ) + { + m_style = wxGRID_FLOAT_FORMAT_COMPACT | + wxGRID_FLOAT_FORMAT_UPPER; + } + else + { + wxLogDebug("Invalid wxGridCellFloatRenderer format " + "parameter string '%s ignored", params); + } + } } } -wxString wxGridCellFloatEditor::GetString() const +wxString wxGridCellFloatEditor::GetString() { - wxString fmt; - if ( m_precision == -1 && m_width != -1) + if ( !m_format ) { - // default precision - fmt.Printf(wxT("%%%d.f"), m_width); - } - else if ( m_precision != -1 && m_width == -1) - { - // default width - fmt.Printf(wxT("%%.%df"), m_precision); - } - else if ( m_precision != -1 && m_width != -1 ) - { - fmt.Printf(wxT("%%%d.%df"), m_width, m_precision); - } - else - { - // default width/precision - fmt = wxT("%f"); + if ( m_precision == -1 && m_width != -1) + { + // default precision + m_format.Printf(wxT("%%%d."), m_width); + } + else if ( m_precision != -1 && m_width == -1) + { + // default width + m_format.Printf(wxT("%%.%d"), m_precision); + } + else if ( m_precision != -1 && m_width != -1 ) + { + m_format.Printf(wxT("%%%d.%d"), m_width, m_precision); + } + else + { + // default width/precision + m_format = wxT("%"); + } + + bool isUpper = (m_style & wxGRID_FLOAT_FORMAT_UPPER) != 0; + if ( m_style & wxGRID_FLOAT_FORMAT_SCIENTIFIC ) + m_format += isUpper ? wxT('E') : wxT('e'); + else if ( m_style & wxGRID_FLOAT_FORMAT_COMPACT ) + m_format += isUpper ? wxT('G') : wxT('g'); + else + m_format += wxT('f'); } - return wxString::Format(fmt, m_value); + return wxString::Format(m_format, m_value); } bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) -- 2.47.2