From 325408f062bfe5c99159f66f0983d6bd344cea3c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 11 Jan 2020 14:03:54 +0100 Subject: [PATCH 1/6] Make wxGridCellAttr ctor taking a single argument explicit There doesn't seem to be any reason for allowing to implicitly convert wxGridCellAttr pointer to wxGridCellAttr object. --- docs/changes.txt | 2 ++ include/wx/generic/grid.h | 7 +++---- interface/wx/grid.h | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index ffb05b5c70..7d8621447f 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -146,6 +146,8 @@ Changes in behaviour which may result in build errors - wxIntProperty::DoValidation() and wxFloatProperty::DoValidation() are no longer public since they are helpers intended for internal use only. +- wxGridCellAttr ctor taking wxGridCellAttr pointer is now explicit. + 3.1.4: (released ????-??-??) ---------------------------- diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 529523c471..3792d96bad 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -428,16 +428,15 @@ public: Merged }; - // ctors - wxGridCellAttr(wxGridCellAttr *attrDefault = NULL) + // default ctor + explicit wxGridCellAttr(wxGridCellAttr *attrDefault = NULL) { Init(attrDefault); SetAlignment(wxALIGN_INVALID, wxALIGN_INVALID); } - // VZ: considering the number of members wxGridCellAttr has now, this ctor - // seems to be pretty useless... may be we should just remove it? + // ctor setting the most common attributes wxGridCellAttr(const wxColour& colText, const wxColour& colBack, const wxFont& font, diff --git a/interface/wx/grid.h b/interface/wx/grid.h index 57cde96b11..12d3330e75 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -912,7 +912,8 @@ public: /** Default constructor. */ - wxGridCellAttr(wxGridCellAttr* attrDefault = NULL); + explicit wxGridCellAttr(wxGridCellAttr* attrDefault = NULL); + /** Constructor specifying some of the often used attributes. */ From f13085441c32269412f3b4fb44d839afe5cb2849 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 11 Jan 2020 18:02:12 +0100 Subject: [PATCH 2/6] Add wxGridFitMode and functions working with it Replace "bool overflow" flag with a class allowing to specify the same overflow/clipping behaviour currently, but also allowing to extend it, notable to add ellipsization support, in the future. Preserve the existing API by reimplementing it in terms of the new one. Also update the same to demonstrate a cell which always overflows, independently of the default cell behaviour. --- include/wx/generic/grid.h | 74 +++++++++++++---- interface/wx/grid.h | 171 +++++++++++++++++++++++++++++++++++++- samples/grid/griddemo.cpp | 3 + src/generic/grid.cpp | 39 ++++++--- 4 files changed, 259 insertions(+), 28 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 3792d96bad..8f31c106ef 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -408,6 +408,42 @@ public: wxRect& rect) const wxOVERRIDE; }; +// ---------------------------------------------------------------------------- +// Helper class used to define What should happen if the cell contents doesn't +// fit into its allotted space. +// ---------------------------------------------------------------------------- + +class wxGridFitMode +{ +public: + // Default ctor creates an object not specifying any particular behaviour. + wxGridFitMode() : m_mode(Mode_Unset) {} + + // Static methods allowing to create objects actually specifying behaviour. + static wxGridFitMode Clip() { return wxGridFitMode(Mode_Clip); } + static wxGridFitMode Overflow() { return wxGridFitMode(Mode_Overflow); } + + // Accessors. + bool IsSpecified() const { return m_mode != Mode_Unset; } + bool IsClip() const { return m_mode == Mode_Clip; } + bool IsOverflow() const { return m_mode == Mode_Overflow; } + + // This one is used in the implementation only. + static wxGridFitMode FromOverflowFlag(bool allow) + { return allow ? Overflow() : Clip(); } + +private: + enum Mode + { + Mode_Unset = -1, + Mode_Overflow, + Mode_Clip + }; + + explicit wxGridFitMode(Mode mode) : m_mode(mode) {} + + Mode m_mode; +}; // ---------------------------------------------------------------------------- // wxGridCellAttr: this class can be used to alter the cells appearance in @@ -462,8 +498,9 @@ public: m_vAlign = vAlign; } void SetSize(int num_rows, int num_cols); + void SetFitMode(wxGridFitMode fitMode) { m_fitMode = fitMode; } void SetOverflow(bool allow = true) - { m_overflow = allow ? Overflow : SingleCell; } + { SetFitMode(wxGridFitMode::FromOverflowFlag(allow)); } void SetReadOnly(bool isReadOnly = true) { m_isReadOnly = isReadOnly ? ReadOnly : ReadWrite; } @@ -486,7 +523,7 @@ public: bool HasRenderer() const { return m_renderer != NULL; } bool HasEditor() const { return m_editor != NULL; } bool HasReadWriteMode() const { return m_isReadOnly != Unset; } - bool HasOverflowMode() const { return m_overflow != UnsetOverflow; } + bool HasOverflowMode() const { return m_fitMode.IsSpecified(); } bool HasSize() const { return m_sizeRows != 1 || m_sizeCols != 1; } const wxColour& GetTextColour() const; @@ -503,8 +540,8 @@ public: void GetNonDefaultAlignment(int *hAlign, int *vAlign) const; void GetSize(int *num_rows, int *num_cols) const; - bool GetOverflow() const - { return m_overflow != SingleCell; } + wxGridFitMode GetFitMode() const; + bool GetOverflow() const { return GetFitMode().IsOverflow(); } wxGridCellRenderer *GetRenderer(const wxGrid* grid, int row, int col) const; wxGridCellEditor *GetEditor(const wxGrid* grid, int row, int col) const; @@ -530,13 +567,6 @@ private: ReadOnly }; - enum wxAttrOverflowMode - { - UnsetOverflow = -1, - Overflow, - SingleCell - }; - // the common part of all ctors void Init(wxGridCellAttr *attrDefault = NULL); @@ -549,7 +579,7 @@ private: int m_sizeRows, m_sizeCols; - wxAttrOverflowMode m_overflow; + wxGridFitMode m_fitMode; wxGridCellRenderer* m_renderer; wxGridCellEditor* m_editor; @@ -1436,8 +1466,14 @@ public: wxFont GetCellFont( int row, int col ) const; void GetDefaultCellAlignment( int *horiz, int *vert ) const; void GetCellAlignment( int row, int col, int *horiz, int *vert ) const; - bool GetDefaultCellOverflow() const; - bool GetCellOverflow( int row, int col ) const; + + wxGridFitMode GetDefaultCellFitMode() const; + wxGridFitMode GetCellFitMode(int row, int col) const; + + bool GetDefaultCellOverflow() const + { return GetDefaultCellFitMode().IsOverflow(); } + bool GetCellOverflow( int row, int col ) const + { return GetCellFitMode(row, col).IsOverflow(); } // this function returns 1 in num_rows and num_cols for normal cells, // positive numbers for a cell spanning multiple columns/rows (as set with @@ -1589,8 +1625,14 @@ public: void SetCellFont( int row, int col, const wxFont& ); void SetDefaultCellAlignment( int horiz, int vert ); void SetCellAlignment( int row, int col, int horiz, int vert ); - void SetDefaultCellOverflow( bool allow ); - void SetCellOverflow( int row, int col, bool allow ); + + void SetDefaultCellFitMode(wxGridFitMode fitMode); + void SetCellFitMode(int row, int col, wxGridFitMode fitMode); + void SetDefaultCellOverflow( bool allow ) + { SetDefaultCellFitMode(wxGridFitMode::FromOverflowFlag(allow)); } + void SetCellOverflow( int row, int col, bool allow ) + { SetCellFitMode(row, col, wxGridFitMode::FromOverflowFlag(allow)); } + void SetCellSize( int row, int col, int num_rows, int num_cols ); // takes ownership of the pointer diff --git a/interface/wx/grid.h b/interface/wx/grid.h index 12d3330e75..0dc3108fc1 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -873,6 +873,81 @@ public: +/** + @class wxGridFitMode + + Allows to specify the behaviour when the cell contents doesn't fit into its + allotted space. + + Objects of this class are used with wxGridCellAttr::SetFitMode() and + wxGrid::SetDefaultCellFitMode() and wxGrid::SetCellFitMode() functions and + allow to specify what should happen if the cell contents doesn't fit into + the available space. The possibilities are: + + - Overflow into the cell to the right if it is empty, or possibly several + cells, if the cell contents still doesn't fit after overflowing into the + immediately neighbouring cell. + - Clip the cell contents, discarding the part which doesn't fit. + + The default behaviour is to overflow, use wxGrid::SetDefaultCellFitMode() + to change this, for example: + @code + grid->SetDefaultCellFitMode(wxGridFitMode::Clip()); + @endcode + + Objects of this class are created using static functions instead of + constructors for better readability and can't be changed after creating + them except by using the assignment operator. + + @library{wxcore} + @category{grid} + + @since 3.1.4 + */ +class wxGridFitMode +{ +public: + /** + Default constructor creates an object not specifying any behaviour. + + This constructor is not very useful, use static methods Clip() and + Overflow() below to create objects of this class instead. + */ + wxGridFitMode(); + + /** + Pseudo-constructor for object specifying clipping behaviour. + */ + static wxGridFitMode Clip(); + + /** + Pseudo-constructor for object specifying overflow behaviour. + */ + static wxGridFitMode Overflow(); + + /** + Return true if the object specifies some particular behaviour. + + This method returns @false for default-constructed objects of this + type only. + */ + bool IsSpecified() const; + + /** + Return true if the object specifies clipping behaviour. + + This method returns @true only for the objects returned by Clip(). + */ + bool IsClip() const; + + /** + Return true if the object specifies overflow behaviour. + + This method returns @true only for the objects returned by Overflow(). + */ + bool IsOverflow() const; +}; + /** @class wxGridCellAttr @@ -1088,7 +1163,29 @@ public: void MergeWith(wxGridCellAttr *mergefrom); void SetSize(int num_rows, int num_cols); + + /** + Specifies the behaviour of the cell contents if it doesn't fit into the + available space. + + @see wxGridFitMode + + @since 3.1.4 + */ + void SetFitMode(wxGridFitMode fitMode); + + /** + Specifies if cells using this attribute should overflow or clip their + contents. + + This is the same as calling SetFitMode() with either + wxGridFitMode::Overflow() or wxGridFitMode::Clip() argument depending + on whether @a allow is @true or @false. + + Prefer using SetFitMode() directly instead in the new code. + */ void SetOverflow(bool allow = true); + void SetKind(wxAttrKind kind); bool HasReadWriteMode() const; @@ -1096,7 +1193,26 @@ public: bool HasSize() const; void GetSize(int *num_rows, int *num_cols) const; + + /** + Returns the fitting mode for the cells using this attribute. + + The returned wxGridFitMode is always specified, i.e. + wxGridFitMode::IsSpecified() always returns @true. The default value, + if SetFitMode() hadn't been called before, is "overflow". + + @since 3.1.4 + */ + wxGridFitMode GetFitMode() const; + + /** + Returns true if the cells using this attribute overflow into the + neighbouring cells. + + Prefer using GetFitMode() in the new code. + */ bool GetOverflow() const; + wxAttrKind GetKind(); @@ -3318,10 +3434,22 @@ public: */ void AutoSizeRows(bool setAsMin = true); + /** + Returns the cell fitting mode. + + @see wxGridFitMode + + @since 3.1.4 + */ + wxGridFitMode GetCellFitMode(int row, int col) const; + /** Returns @true if the cell value can overflow. - A cell can overflow if the next cell in the row is empty. + This is identical to calling GetCellFitMode() and using + wxGridFitMode::IsOverflow() on the returned value. + + Prefer using GetCellFitMode() directly in the new code. */ bool GetCellOverflow(int row, int col) const; @@ -3350,8 +3478,25 @@ public: */ bool IsColShown(int col) const; + /** + Returns the default cell fitting mode. + + The default mode is "overflow", but can be modified using + SetDefaultCellFitMode(). + + @see wxGridFitMode + + @since 3.1.4 + */ + wxGridFitMode GetDefaultCellFitMode() const; + /** Returns @true if the cells can overflow by default. + + This is identical to calling GetDefaultCellFitMode() and using + wxGridFitMode::IsOverflow() on the returned value. + + Prefer using GetDefaultCellFitMode() directly in the new code. */ bool GetDefaultCellOverflow() const; @@ -3400,8 +3545,20 @@ public: */ bool IsRowShown(int row) const; + /** + Specifies the behaviour of the cell contents if it doesn't fit into the + available space. + + @see wxGridFitMode + + @since 3.1.4 + */ + void SetCellFitMode(int row, int col, wxGridFitMode fitMode); + /** Sets the overflow permission of the cell. + + Prefer using SetCellFitMode() in the new code. */ void SetCellOverflow(int row, int col, bool allow); @@ -3470,8 +3627,20 @@ public: void ShowCol(int col); + /** + Specifies the default behaviour of the cell contents if it doesn't fit + into the available space. + + @see wxGridFitMode + + @since 3.1.4 + */ + void SetDefaultCellFitMode(wxGridFitMode fitMode); + /** Sets the default overflow permission of the cells. + + Prefer using SetDefaultCellFitMode() in the new code. */ void SetDefaultCellOverflow( bool allow ); diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp index df7810c7d6..0560c38319 100644 --- a/samples/grid/griddemo.cpp +++ b/samples/grid/griddemo.cpp @@ -501,6 +501,9 @@ GridFrame::GridFrame() grid->SetCellValue( 99, 99, "Ctrl+End\nwill go to\nthis cell" ); grid->SetCellValue( 1, 0, "This default cell will overflow into neighboring cells, but not if you turn overflow off."); + grid->SetCellValue(2, 0, "This one always overflows"); + grid->SetCellFitMode(2, 0, wxGridFitMode::Overflow()); + grid->SetCellTextColour(1, 2, *wxRED); grid->SetCellBackgroundColour(1, 2, *wxGREEN); diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index c40e026a73..3cacdc3810 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -409,7 +409,6 @@ void wxGridCellAttr::Init(wxGridCellAttr *attrDefault) m_attrkind = wxGridCellAttr::Cell; m_sizeRows = m_sizeCols = 1; - m_overflow = UnsetOverflow; SetDefAttr(attrDefault); } @@ -443,7 +442,7 @@ wxGridCellAttr *wxGridCellAttr::Clone() const if ( IsReadOnly() ) attr->SetReadOnly(); - attr->SetOverflow( m_overflow == Overflow ); + attr->m_fitMode = m_fitMode; attr->SetKind( m_attrkind ); return attr; @@ -626,6 +625,23 @@ void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const *num_cols = m_sizeCols; } +wxGridFitMode wxGridCellAttr::GetFitMode() const +{ + if ( m_fitMode.IsSpecified() ) + { + return m_fitMode; + } + else if (m_defGridAttr && m_defGridAttr != this) + { + return m_defGridAttr->GetFitMode(); + } + else + { + wxFAIL_MSG(wxT("Missing default cell attribute")); + return wxGridFitMode(); + } +} + // GetRenderer and GetEditor use a slightly different decision path about // which attribute to use. If a non-default attr object has one then it is // used, otherwise the default editor or renderer is fetched from the grid and @@ -2383,6 +2399,7 @@ void wxGrid::Create() m_defaultCellAttr->SetAlignment(wxALIGN_LEFT, wxALIGN_TOP); m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer); m_defaultCellAttr->SetEditor(new wxGridCellTextEditor); + m_defaultCellAttr->SetFitMode(wxGridFitMode::Overflow()); #if _USE_VISATTR wxVisualAttributes gva = wxListBox::GetClassDefaultAttributes(); @@ -8441,9 +8458,9 @@ void wxGrid::SetDefaultCellAlignment( int horiz, int vert ) m_defaultCellAttr->SetAlignment(horiz, vert); } -void wxGrid::SetDefaultCellOverflow( bool allow ) +void wxGrid::SetDefaultCellFitMode(wxGridFitMode fitMode) { - m_defaultCellAttr->SetOverflow(allow); + m_defaultCellAttr->SetFitMode(fitMode); } void wxGrid::SetDefaultCellFont( const wxFont& font ) @@ -8494,9 +8511,9 @@ void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) const m_defaultCellAttr->GetAlignment(horiz, vert); } -bool wxGrid::GetDefaultCellOverflow() const +wxGridFitMode wxGrid::GetDefaultCellFitMode() const { - return m_defaultCellAttr->GetOverflow(); + return m_defaultCellAttr->GetFitMode(); } wxGridCellRenderer *wxGrid::GetDefaultRenderer() const @@ -8547,13 +8564,13 @@ void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) const attr->DecRef(); } -bool wxGrid::GetCellOverflow( int row, int col ) const +wxGridFitMode wxGrid::GetCellFitMode( int row, int col ) const { wxGridCellAttr *attr = GetCellAttr(row, col); - bool allow = attr->GetOverflow(); + wxGridFitMode fitMode = attr->GetFitMode(); attr->DecRef(); - return allow; + return fitMode; } wxGrid::CellSpan @@ -8854,12 +8871,12 @@ void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert ) } } -void wxGrid::SetCellOverflow( int row, int col, bool allow ) +void wxGrid::SetCellFitMode( int row, int col, wxGridFitMode fitMode ) { if ( CanHaveAttributes() ) { wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->SetOverflow(allow); + attr->SetFitMode(fitMode); attr->DecRef(); } } From 41dcd9ecdbce8ab4dae09ed5861e3f10873b03bf Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 11 Jan 2020 18:25:55 +0100 Subject: [PATCH 3/6] Add API for ellipsization support to wxGrid This API is not implemented yet, i.e. ellipsization mode is not respected for now. This commit just adds the API, documents it and adds an example of using it in the sample. --- include/wx/generic/grid.h | 30 +++++++++++++++++++++++++++++- interface/wx/grid.h | 17 +++++++++++++++++ samples/grid/griddemo.cpp | 6 ++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 8f31c106ef..99645ba7cc 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -422,12 +422,35 @@ public: // Static methods allowing to create objects actually specifying behaviour. static wxGridFitMode Clip() { return wxGridFitMode(Mode_Clip); } static wxGridFitMode Overflow() { return wxGridFitMode(Mode_Overflow); } + static wxGridFitMode Ellipsize(wxEllipsizeMode ellipsize = wxELLIPSIZE_END) + { + // This cast works because the enum elements are the same, see below. + return wxGridFitMode(static_cast(ellipsize)); + } // Accessors. bool IsSpecified() const { return m_mode != Mode_Unset; } bool IsClip() const { return m_mode == Mode_Clip; } bool IsOverflow() const { return m_mode == Mode_Overflow; } + wxEllipsizeMode GetEllipsizeMode() const + { + switch ( m_mode ) + { + case Mode_Unset: + case Mode_EllipsizeStart: + case Mode_EllipsizeMiddle: + case Mode_EllipsizeEnd: + return static_cast(m_mode); + + case Mode_Overflow: + case Mode_Clip: + break; + } + + return wxELLIPSIZE_NONE; + } + // This one is used in the implementation only. static wxGridFitMode FromOverflowFlag(bool allow) { return allow ? Overflow() : Clip(); } @@ -435,7 +458,12 @@ public: private: enum Mode { - Mode_Unset = -1, + // This is a hack to save space: the first 4 elements of this enum are + // the same as those of wxEllipsizeMode. + Mode_Unset = wxELLIPSIZE_NONE, + Mode_EllipsizeStart = wxELLIPSIZE_START, + Mode_EllipsizeMiddle = wxELLIPSIZE_MIDDLE, + Mode_EllipsizeEnd = wxELLIPSIZE_END, Mode_Overflow, Mode_Clip }; diff --git a/interface/wx/grid.h b/interface/wx/grid.h index 0dc3108fc1..81a372cff3 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -888,6 +888,9 @@ public: cells, if the cell contents still doesn't fit after overflowing into the immediately neighbouring cell. - Clip the cell contents, discarding the part which doesn't fit. + - Ellipsize the cell contents, i.e. replace the non-fitting part with + ellipsis (@c ...), putting the ellipsis at the end by default, but possibly + at the beginning or in the middle. The default behaviour is to overflow, use wxGrid::SetDefaultCellFitMode() to change this, for example: @@ -925,6 +928,11 @@ public: */ static wxGridFitMode Overflow(); + /** + Pseudo-constructor for object specifying ellipsize behaviour. + */ + static wxGridFitMode Ellipsize(wxEllipsizeMode ellipsize = wxELLIPSIZE_END); + /** Return true if the object specifies some particular behaviour. @@ -946,6 +954,15 @@ public: This method returns @true only for the objects returned by Overflow(). */ bool IsOverflow() const; + + /** + Return ellipsize mode, possibly @c wxELLIPSIZE_NONE. + + For the objects constructed using Ellipsize(), the same ellipsization + mode as was passed to it is returned. For all the other objects, + ::wxELLIPSIZE_NONE is. + */ + wxEllipsizeMode GetEllipsizeMode() const; }; /** diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp index 0560c38319..b76d441ef7 100644 --- a/samples/grid/griddemo.cpp +++ b/samples/grid/griddemo.cpp @@ -588,6 +588,12 @@ GridFrame::GridFrame() grid->SetCellRenderer(14, 1, new wxGridCellDateRenderer("%Y-%m-%d")); grid->SetCellEditor(14, 1, new wxGridCellDateEditor); + grid->SetCellValue(13, 3, "String using default ellipsization"); + grid->SetCellFitMode(13, 3, wxGridFitMode::Ellipsize()); + + grid->SetCellValue(13, 4, "String ellipsized in the middle"); + grid->SetCellFitMode(13, 4, wxGridFitMode::Ellipsize(wxELLIPSIZE_MIDDLE)); + const wxString choices[] = { "Please select a choice", From 46042843e817e70e4acf66be34e6529d064b8be7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 11 Jan 2020 19:15:15 +0100 Subject: [PATCH 4/6] Implement support for ellipsization mode in wxGrid Add another wxGrid::DrawTextRectangle() overload, taking wxGridCellAttr and ellipsizing the string if necessary, i.e. if the fitting mode of this attribute indicates that we should do it. Switch the code of all renderers for which it makes sense to use ellipsization to use the new overload. --- include/wx/generic/grid.h | 7 ++++++ src/generic/grid.cpp | 22 +++++++++++++++++++ src/generic/gridctrl.cpp | 46 +++++++++++++++------------------------ 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 99645ba7cc..d4e403e8eb 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -1160,6 +1160,13 @@ public: int verticalAlignment = wxALIGN_TOP, int textOrientation = wxHORIZONTAL ) const; + void DrawTextRectangle(wxDC& dc, + const wxString& text, + const wxRect& rect, + const wxGridCellAttr& attr, + int defaultHAlign = wxALIGN_INVALID, + int defaultVAlign = wxALIGN_INVALID); + // ------ grid render function for printing // void Render( wxDC& dc, diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 3cacdc3810..68bcc9afc4 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -6822,6 +6822,28 @@ void wxGrid::DrawTextRectangle(wxDC& dc, } } +void wxGrid::DrawTextRectangle(wxDC& dc, + const wxString& text, + const wxRect& rect, + const wxGridCellAttr& attr, + int hAlign, + int vAlign) +{ + attr.GetNonDefaultAlignment(&hAlign, &vAlign); + + // This does nothing if there is no need to ellipsize. + const wxString& ellipsizedText = wxControl::Ellipsize + ( + text, + dc, + attr.GetFitMode().GetEllipsizeMode(), + rect.GetWidth(), + wxELLIPSIZE_FLAGS_NONE + ); + + DrawTextRectangle(dc, ellipsizedText, rect, hAlign, vAlign); +} + // Split multi-line text up into an array of strings. // Any existing contents of the string array are preserved. // diff --git a/src/generic/gridctrl.cpp b/src/generic/gridctrl.cpp index 585a8e6341..9a3a728696 100644 --- a/src/generic/gridctrl.cpp +++ b/src/generic/gridctrl.cpp @@ -148,15 +148,12 @@ void wxGridCellDateRenderer::Draw(wxGrid& grid, SetTextColoursAndFont(grid, attr, dc, isSelected); - // draw the text right aligned by default - int hAlign = wxALIGN_RIGHT, - vAlign = wxALIGN_INVALID; - attr.GetNonDefaultAlignment(&hAlign, &vAlign); - wxRect rect = rectCell; rect.Inflate(-1); - grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); + // draw the text right aligned by default + grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr, + wxALIGN_RIGHT); } wxSize wxGridCellDateRenderer::GetBestSize(wxGrid& grid, @@ -246,15 +243,12 @@ void wxGridCellEnumRenderer::Draw(wxGrid& grid, SetTextColoursAndFont(grid, attr, dc, isSelected); - // draw the text right aligned by default - int hAlign = wxALIGN_RIGHT, - vAlign = wxALIGN_INVALID; - attr.GetNonDefaultAlignment(&hAlign, &vAlign); - wxRect rect = rectCell; rect.Inflate(-1); - grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); + // draw the text right aligned by default + grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr, + wxALIGN_RIGHT); } wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid, @@ -308,6 +302,8 @@ wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid, wxRect rect = rectCell; rect.Inflate(-1); + // Do not use here the overload taking the attribute, as this would + // ellipsize the text, which is never necessary with this renderer. grid.DrawTextRectangle(dc, GetTextLines(grid,dc,attr,rect,row,col), rect, horizAlign, vertAlign); } @@ -595,11 +591,11 @@ void wxGridCellStringRenderer::Draw(wxGrid& grid, // erase only this cells background, overflow cells should have been erased wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - if (attr.GetOverflow()) { + int hAlign, vAlign; + attr.GetAlignment(&hAlign, &vAlign); + int overflowCols = 0; int cols = grid.GetNumberCols(); int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth(); @@ -675,7 +671,7 @@ void wxGridCellStringRenderer::Draw(wxGrid& grid, SetTextColoursAndFont(grid, attr, dc, isSelected); grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), - rect, hAlign, vAlign); + rect, attr); } // ---------------------------------------------------------------------------- @@ -709,15 +705,12 @@ void wxGridCellNumberRenderer::Draw(wxGrid& grid, SetTextColoursAndFont(grid, attr, dc, isSelected); - // draw the text right aligned by default - int hAlign = wxALIGN_RIGHT, - vAlign = wxALIGN_INVALID; - attr.GetNonDefaultAlignment(&hAlign, &vAlign); - wxRect rect = rectCell; rect.Inflate(-1); - grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); + // draw the text right aligned by default + grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr, + wxALIGN_RIGHT); } wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid, @@ -824,15 +817,12 @@ void wxGridCellFloatRenderer::Draw(wxGrid& grid, SetTextColoursAndFont(grid, attr, dc, isSelected); - // draw the text right aligned by default - int hAlign = wxALIGN_RIGHT, - vAlign = wxALIGN_INVALID; - attr.GetNonDefaultAlignment(&hAlign, &vAlign); - wxRect rect = rectCell; rect.Inflate(-1); - grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); + // draw the text right aligned by default + grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr, + wxALIGN_RIGHT); } wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid, From 13752968eaac3cdd7fec878ed9a7c6886b8a9fb3 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 11 Jan 2020 23:13:02 +0100 Subject: [PATCH 5/6] Fix closing minimized top level windows under Windows 10 Minimized windows don't seem to get any events after "Close" menu item is selected from the system menu, so they were never actually destroyed when closing them in this way. Fix this by explicitly waking up the message loop after deleting the window to ensure that the delayed destruction does happen. Closes #18622. See https://github.com/wxWidgets/wxWidgets/pull/1690 --- include/wx/msw/toplevel.h | 1 + src/msw/toplevel.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/wx/msw/toplevel.h b/include/wx/msw/toplevel.h index 5cef6b1e8a..cf6356754a 100644 --- a/include/wx/msw/toplevel.h +++ b/include/wx/msw/toplevel.h @@ -55,6 +55,7 @@ public: virtual bool IsIconized() const wxOVERRIDE; virtual void SetIcons(const wxIconBundle& icons ) wxOVERRIDE; virtual void Restore() wxOVERRIDE; + virtual bool Destroy() wxOVERRIDE; virtual void SetLayoutDirection(wxLayoutDirection dir) wxOVERRIDE; diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index e954f19d14..0a7de130e2 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -823,6 +823,22 @@ void wxTopLevelWindowMSW::Restore() DoShowWindow(SW_RESTORE); } +bool wxTopLevelWindowMSW::Destroy() +{ + if ( !wxTopLevelWindowBase::Destroy() ) + return false; + + // Under Windows 10 iconized windows don't get any messages, so delayed + // destruction doesn't work for them if we don't force a message dispatch + // here (and it doesn't seem useful to test for MSWIsIconized() as doing + // this doesn't do any harm for non-iconized windows neither). For that + // matter, doing this shouldn't do any harm under previous OS versions + // neither, so checking for the OS version doesn't seem useful too. + wxWakeUpIdle(); + + return true; +} + void wxTopLevelWindowMSW::SetLayoutDirection(wxLayoutDirection dir) { if ( dir == wxLayout_Default ) From 1b6856931a6627f9507d50bd81c07873578418e1 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 11 Jan 2020 23:36:38 +0100 Subject: [PATCH 6/6] Fix problem with dragged icon remaining on screen under MSW 10 Always perform cleanup on drop, even if OnDrop() threw an exception. Closes #18499. --- src/msw/ole/droptgt.cpp | 53 ++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/msw/ole/droptgt.cpp b/src/msw/ole/droptgt.cpp index acb7e44017..bad5a64884 100644 --- a/src/msw/ole/droptgt.cpp +++ b/src/msw/ole/droptgt.cpp @@ -371,6 +371,45 @@ STDMETHODIMP wxIDropTarget::Drop(IDataObject *pIDataSource, wxLogLastError(wxT("ScreenToClient")); } + // Initialize it to a safe value in case OnDrop() throws. + *pdwEffect = DROPEFFECT_NONE; + + // Create a guard that will clean things up in case of exception: we + // must perform it in any case, as if we don't update the drag image it + // would remain on screen under Windows 10, see #18499. + class DropCleanup + { + public: + DropCleanup(wxCOMPtr& pIDataObject, + wxDropTarget* pTarget, + POINTL pt, + DWORD* pdwEffect) + : m_pIDataObject(pIDataObject), + m_pTarget(pTarget), + m_pt(pt), + m_pdwEffect(pdwEffect) + { + } + + ~DropCleanup() + { + // release the held object + m_pIDataObject.reset(); + + // update drag image + m_pTarget->MSWUpdateDragImageOnData + ( + m_pt.x, m_pt.y, + ConvertDragEffectToResult(*m_pdwEffect) + ); + } + private: + wxCOMPtr& m_pIDataObject; + wxDropTarget* m_pTarget; + DWORD* m_pdwEffect; + POINTL m_pt; + } dropCleanup(m_pIDataObject, m_pTarget, pt, pdwEffect); + // first ask the drop target if it wants data if ( m_pTarget->OnDrop(pt.x, pt.y) ) { // it does, so give it the data source @@ -384,21 +423,7 @@ STDMETHODIMP wxIDropTarget::Drop(IDataObject *pIDataSource, // operation succeeded *pdwEffect = ConvertDragResultToEffect(rc); } - else { - *pdwEffect = DROPEFFECT_NONE; - } } - else { - // OnDrop() returned false, no need to copy data - *pdwEffect = DROPEFFECT_NONE; - } - - // release the held object - m_pIDataObject.reset(); - - // update drag image - m_pTarget->MSWUpdateDragImageOnData(pt.x, pt.y, - ConvertDragEffectToResult(*pdwEffect)); return S_OK; }