From d87abd132e037ff836e9744e1a79c265abd86b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Fri, 31 Jul 2020 16:36:50 +0200 Subject: [PATCH 001/105] Do not try to create bitmap for default constructed Caret If a Caret is default-constructed, the width and height are still 0, and the wxBitmap::Create implementations expect valid sizes. The same applies for the bitmap after a size change. --- src/generic/caret.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/generic/caret.cpp b/src/generic/caret.cpp index 0f5aa7ac51..603888570b 100644 --- a/src/generic/caret.cpp +++ b/src/generic/caret.cpp @@ -103,7 +103,8 @@ void wxCaret::InitGeneric() #ifndef wxHAS_CARET_USING_OVERLAYS m_xOld = m_yOld = -1; - m_bmpUnderCaret.Create(m_width, m_height); + if (m_width && m_height) + m_bmpUnderCaret.Create(m_width, m_height); #endif } @@ -174,7 +175,10 @@ void wxCaret::DoSize() m_overlay.Reset(); #else // Change bitmap size - m_bmpUnderCaret = wxBitmap(m_width, m_height); + if (m_width && m_height) + m_bmpUnderCaret = wxBitmap(m_width, m_height); + else + m_bmpUnderCaret = wxBitmap(); #endif if (countVisible > 0) { From b8a4b96243a3fe992c6c4840c69c16fbc3b07a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Mon, 31 Aug 2020 16:45:20 +0200 Subject: [PATCH 002/105] Create underlying bitmap for caret when it is explicitly created wxCaret::Create implies a size change, so call DoSize to initialize the underlying wxBitmap. --- include/wx/caret.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/wx/caret.h b/include/wx/caret.h index e6e9728ff8..b625b5f0ac 100644 --- a/include/wx/caret.h +++ b/include/wx/caret.h @@ -153,6 +153,7 @@ protected: m_window = window; m_width = width; m_height = height; + DoSize(); return true; } From 92ea83f00b4f444112cc59bd873c7b17724fa85d Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Thu, 17 Sep 2020 22:35:22 +0200 Subject: [PATCH 003/105] First implementation --- include/wx/gtk/radiobut.h | 2 +- include/wx/gtk1/radiobut.h | 2 +- include/wx/motif/radiobut.h | 2 +- include/wx/msw/radiobut.h | 2 +- include/wx/osx/radiobut.h | 2 +- include/wx/qt/radiobut.h | 2 +- include/wx/radiobut.h | 39 +++++++++++++++++++++++++++++++++++++ include/wx/univ/radiobut.h | 2 +- 8 files changed, 46 insertions(+), 7 deletions(-) diff --git a/include/wx/gtk/radiobut.h b/include/wx/gtk/radiobut.h index cf6492a623..b85f8ea723 100644 --- a/include/wx/gtk/radiobut.h +++ b/include/wx/gtk/radiobut.h @@ -13,7 +13,7 @@ // wxRadioButton //----------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton: public wxControl +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { public: wxRadioButton() { } diff --git a/include/wx/gtk1/radiobut.h b/include/wx/gtk1/radiobut.h index d958079729..662b681d74 100644 --- a/include/wx/gtk1/radiobut.h +++ b/include/wx/gtk1/radiobut.h @@ -13,7 +13,7 @@ // wxRadioButton //----------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton: public wxControl +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { public: wxRadioButton() { } diff --git a/include/wx/motif/radiobut.h b/include/wx/motif/radiobut.h index 43414438a7..5759f01162 100644 --- a/include/wx/motif/radiobut.h +++ b/include/wx/motif/radiobut.h @@ -11,7 +11,7 @@ #ifndef _WX_RADIOBUT_H_ #define _WX_RADIOBUT_H_ -class WXDLLIMPEXP_CORE wxRadioButton: public wxControl +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { wxDECLARE_DYNAMIC_CLASS(wxRadioButton); public: diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h index a568316edf..0554881601 100644 --- a/include/wx/msw/radiobut.h +++ b/include/wx/msw/radiobut.h @@ -13,7 +13,7 @@ #include "wx/msw/ownerdrawnbutton.h" -class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton +class WXDLLIMPEXP_CORE wxRadioButton : public public wxRadioButtonBase> { public: // ctors and creation functions diff --git a/include/wx/osx/radiobut.h b/include/wx/osx/radiobut.h index e968d80acd..cf74f14d89 100644 --- a/include/wx/osx/radiobut.h +++ b/include/wx/osx/radiobut.h @@ -11,7 +11,7 @@ #ifndef _WX_RADIOBUT_H_ #define _WX_RADIOBUT_H_ -class WXDLLIMPEXP_CORE wxRadioButton: public wxControl +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { wxDECLARE_DYNAMIC_CLASS(wxRadioButton); diff --git a/include/wx/qt/radiobut.h b/include/wx/qt/radiobut.h index 5a1ab5ad14..1502173105 100644 --- a/include/wx/qt/radiobut.h +++ b/include/wx/qt/radiobut.h @@ -10,7 +10,7 @@ class QRadioButton; -class WXDLLIMPEXP_CORE wxRadioButton : public wxControl +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: wxRadioButton(); diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index 11f466cdbe..dec331af73 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -32,6 +32,45 @@ #include "wx/control.h" +class WXDLLIMPEXP_FWD_CORE wxRadioButton; + +wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn); +wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn); +wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn); +wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn); + +template +class WXDLLIMPEXP_CORE wxRadioButtonBase : public W +{ +public: + typedef W BaseWindowClass; + + wxRadioButtonBase() { } + + wxRadioButton* GetFirstInGroup() const + { + return wxGetFirstButtonInGroup( static_cast(this)); + } + + wxRadioButton* GetLastInGroup() const + { + return wxGetLastButtonInGroup( static_cast(this)); + } + + wxRadioButton* GetPreviousInGroup() const + { + return wxGetPreviousButtonInGroup( static_cast(this)); + } + + wxRadioButton* GetNextInGroup() const + { + return wxGetNextButtonInGroup( static_cast(this)); + } + +private: + wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxRadioButtonBase, W); +}; + extern WXDLLIMPEXP_DATA_CORE(const char) wxRadioButtonNameStr[]; #if defined(__WXUNIVERSAL__) diff --git a/include/wx/univ/radiobut.h b/include/wx/univ/radiobut.h index ae16aa25ce..0b6580a2ab 100644 --- a/include/wx/univ/radiobut.h +++ b/include/wx/univ/radiobut.h @@ -17,7 +17,7 @@ // wxRadioButton // ---------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton : public wxCheckBox +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: // constructors From 552dbbe26eae729f77a05799e9b7a926373c8754 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Thu, 17 Sep 2020 22:46:18 +0200 Subject: [PATCH 004/105] Removing const for first version --- include/wx/radiobut.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index dec331af73..02dadc5ff9 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -47,22 +47,22 @@ public: wxRadioButtonBase() { } - wxRadioButton* GetFirstInGroup() const + wxRadioButton* GetFirstInGroup() { return wxGetFirstButtonInGroup( static_cast(this)); } - wxRadioButton* GetLastInGroup() const + wxRadioButton* GetLastInGroup() { return wxGetLastButtonInGroup( static_cast(this)); } - wxRadioButton* GetPreviousInGroup() const + wxRadioButton* GetPreviousInGroup() { return wxGetPreviousButtonInGroup( static_cast(this)); } - wxRadioButton* GetNextInGroup() const + wxRadioButton* GetNextInGroup() { return wxGetNextButtonInGroup( static_cast(this)); } From 200c1af6978af783899e2dfcc7361de187451461 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Thu, 17 Sep 2020 23:13:44 +0200 Subject: [PATCH 005/105] Going private with the implementations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although they’re still exported of course … --- include/wx/radiobut.h | 19 +++++++++++-------- src/common/containr.cpp | 19 ++++++++++++------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index 02dadc5ff9..182ae9c8c5 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -34,10 +34,13 @@ class WXDLLIMPEXP_FWD_CORE wxRadioButton; -wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn); -wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn); -wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn); -wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn); +namespace wxPrivate +{ + WXDLLIMPEXP_CORE wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn); +} // namespace wxPrivate template class WXDLLIMPEXP_CORE wxRadioButtonBase : public W @@ -49,22 +52,22 @@ public: wxRadioButton* GetFirstInGroup() { - return wxGetFirstButtonInGroup( static_cast(this)); + return wxPrivate::wxGetFirstButtonInGroup( static_cast(this)); } wxRadioButton* GetLastInGroup() { - return wxGetLastButtonInGroup( static_cast(this)); + return wxPrivate::wxGetLastButtonInGroup( static_cast(this)); } wxRadioButton* GetPreviousInGroup() { - return wxGetPreviousButtonInGroup( static_cast(this)); + return wxPrivate::wxGetPreviousButtonInGroup( static_cast(this)); } wxRadioButton* GetNextInGroup() { - return wxGetNextButtonInGroup( static_cast(this)); + return wxPrivate::wxGetNextButtonInGroup( static_cast(this)); } private: diff --git a/src/common/containr.cpp b/src/common/containr.cpp index b418a3b8c2..9bcdbab781 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -240,6 +240,9 @@ void wxControlContainer::SetLastFocus(wxWindow *win) #if wxUSE_RADIOBTN +namespace wxPrivate +{ + wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) { if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) @@ -348,6 +351,8 @@ wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) return NULL; } +} // namespace wxPrivate + #endif // wxUSE_RADIOBTN // ---------------------------------------------------------------------------- @@ -468,7 +473,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // If we are in a radio button group, start from the first item in the // group if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) - winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); + winFocus = wxPrivate::wxGetFirstButtonInGroup((wxRadioButton*)winFocus); #endif // USE_RADIOBTN_NAV // ok, we found the focus - now is it our child? start_node = children.Find( winFocus ); @@ -564,7 +569,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) if ( child->HasFlag(wxRB_GROUP) ) { // need to tab into the active button within a group - wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child); + wxRadioButton *rb = wxPrivate::wxGetSelectedButtonInGroup((wxRadioButton*)child); if ( rb ) child = rb; } @@ -586,20 +591,20 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // find the correct radio button to focus if ( forward ) { - child = wxGetNextButtonInGroup(lastBtn); + child = wxPrivate::wxGetNextButtonInGroup(lastBtn); if ( !child ) { // no next button in group, set it to the first button - child = wxGetFirstButtonInGroup(lastBtn); + child = wxPrivate::wxGetFirstButtonInGroup(lastBtn); } } else { - child = wxGetPreviousButtonInGroup(lastBtn); + child = wxPrivate::wxGetPreviousButtonInGroup(lastBtn); if ( !child ) { // no previous button in group, set it to the last button - child = wxGetLastButtonInGroup(lastBtn); + child = wxPrivate::wxGetLastButtonInGroup(lastBtn); } } @@ -764,7 +769,7 @@ bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused) wxRadioButton* btn = wxDynamicCast(child, wxRadioButton); if (btn) { - wxRadioButton* selected = wxGetSelectedButtonInGroup(btn); + wxRadioButton* selected = wxPrivate::wxGetSelectedButtonInGroup(btn); if (selected) child = selected; } From 593e6a9ca680d35bd0734ba6ab62e3db52f80e1f Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Sun, 20 Sep 2020 18:35:51 +0200 Subject: [PATCH 006/105] Update include/wx/msw/radiobut.h Co-authored-by: VZ --- include/wx/msw/radiobut.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h index 0554881601..fc6d2a8949 100644 --- a/include/wx/msw/radiobut.h +++ b/include/wx/msw/radiobut.h @@ -13,7 +13,7 @@ #include "wx/msw/ownerdrawnbutton.h" -class WXDLLIMPEXP_CORE wxRadioButton : public public wxRadioButtonBase> +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase< wxMSWOwnerDrawnButton > { public: // ctors and creation functions From 02b3b9d745cc434419b5f94c96820b8dc3bca64a Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Sun, 20 Sep 2020 19:44:16 +0200 Subject: [PATCH 007/105] Adding docs --- interface/wx/radiobut.h | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index d037412e55..0257bc31ce 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -14,7 +14,9 @@ You can create a group of mutually-exclusive radio buttons by specifying @c wxRB_GROUP for the first in the group. The group ends when another - radio button group is created, or there are no more radio buttons. + radio button group is created, or there are no more radio buttons. You can navigate + among the items in a group with @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() + @beginStyleTable @style{wxRB_GROUP} @@ -119,5 +121,33 @@ public: @true to check, @false to uncheck. */ virtual void SetValue(bool value); + + /** + Returns the first radio button of the @c wxRB_GROUP this instance is in. + + @see GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() + */ + wxRadioButton* GetFirstInGroup(); + + /** + Returns the last radio button of the @c wxRB_GROUP this instance is in. + + @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() + */ + wxRadioButton* GetLastInGroup(); + + /** + Returns the previous radio button of the @c wxRB_GROUP this instance is in. + + @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup() + */ + wxRadioButton* GetPreviousInGroup(); + + /** + Returns the next radio button of the @c wxRB_GROUP this instance is in. + + @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup() + */ + wxRadioButton* GetNextInGroup(); }; From 44c2671e7b14fa841e02552f11a586bc87d35ebf Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 02:10:27 +0200 Subject: [PATCH 008/105] Add initial draft of high DPI overview Add a topic covering high DPI support. --- docs/doxygen/mainpages/topics.h | 1 + docs/doxygen/overviews/high_dpi.md | 121 +++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 docs/doxygen/overviews/high_dpi.md diff --git a/docs/doxygen/mainpages/topics.h b/docs/doxygen/mainpages/topics.h index 7a0a6228b5..ceb5b4c6ea 100644 --- a/docs/doxygen/mainpages/topics.h +++ b/docs/doxygen/mainpages/topics.h @@ -99,5 +99,6 @@ topics related to building applications with wxWidgets. @li @subpage overview_windowdeletion @li @subpage overview_envvars @li @subpage overview_customwidgets +@li @subpage overview_high_dpi */ diff --git a/docs/doxygen/overviews/high_dpi.md b/docs/doxygen/overviews/high_dpi.md new file mode 100644 index 0000000000..83daf480f6 --- /dev/null +++ b/docs/doxygen/overviews/high_dpi.md @@ -0,0 +1,121 @@ +High DPI Support in wxWidgets {#overview_high_dpi} +============================= +[TOC] + +[comment]: # (Not sure if the first 2 sections are really worth keeping) + +Terms and Definitions +===================== + +Many modern displays have much higher pixel density than used to be the norm, +resulting in much higher values of DPI (dots, i.e. pixels, per inch) than the +traditionally used values. While the DPI reported by the system is not exactly +the same as the actual pixel density, i.e. it doesn't exactly correspond to the +number of pixels on the screen divided by the screen physical dimension in +inches, it still needs to change to roughly correspond to it. + +This system DPI value is typically expressed using a scaling factor, by which +the baseline DPI value is multiplied. For example, MSW systems may use 125% or +150% scaling, meaning that they use DPI of 120 or 144 respectively, as baseline +DPI value is 96. Similarly, Linux systems may use "2x" scaling, resulting in +DPI value of 192. Macs are slightly different, as even they also may use "2x" +scaling, the effective DPI corresponding to it is 144, as the baseline value on +this platform is 72. + + +The Problem with High DPI Displays +================================== + +If high DPI displays were treated in the same way as normal ones, existing +applications would look tiny of them. For example, a square window 500 pixels +in size would take half of a standard 1920×1080 ("Full HD") display vertically, +but only a quarter on a 3840×2160 ("4K UHD") display. To prevent this from +happening, most platforms automatically scale the windows by the scaling +factor, defined above, when displaying them on high DPI displays. In this +example, scaling factor is 2 and so the actual size of the window on screen +would become 1000 when automatic scaling is in effect. + +Automatic scaling is convenient, but doesn't really allow the application to +use the extra pixels available on the display. Visually, this means that the +scaled application appears blurry, in contrast to sharper applications using +the full display resolution, so a better solution is needed. + + +Pixel Values in High DPI +======================== + +Some systems automatically scale all the coordinates by the DPI scaling factor, +however not all systems supported by wxWidgets do it -- notably, MSW does not. +This means that "logical pixels", in which all coordinates and sizes are +expressed in wxWidgets API, do _not_ have the same meaning on all platforms +when using high DPI displays. To hide this difference from the application, +wxWidgets provides "device-independent pixels", abbreviated as "DIP", that are +always of the same size on all displays and all platforms. + +Thus, the first thing do when preparing your application for high DPI support +is to stop using raw pixel values. Actually, using any pixel values is not +recommended and replacing them with the values based on the text metrics, i.e. +obtained using wxWindow::GetTextExtent(), or expressing them in dialog units +(see wxWindow::ConvertDialogToPixels()) is preferable. However the simplest +change is to just replace the pixel values with the values in DIP: for this, +just use wxWindow::FromDIP() to convert from one to the other. + +For example, if you have the existing code: +```cpp +myFrame->SetClientSize(wxSize(400, 300)); +``` +you can just replace it with +```cpp +myFrame->SetClientSize(myFrame->FromDIP(wxSize(400, 300))); +``` + + +Physical Pixels +=============== + +In addition to (logical) pixels and DIPs discussed above, you may also need to +work in physical pixel coordinates, corresponding to the actual display pixels. +Physical pixels are never scaled, on any platform, and must be used when +drawing graphics elements to ensure that the best possible resolution is used. +For example, all operations on wxGLCanvas use physical pixels. + +To convert between logical and physical pixels, you can use +wxWindow::GetContentScaleFactor(): this is a value greater than or equal to 1, +so a value in logical pixels needs to be multiplied by it in order to obtain +the value in physical pixels. + +For example, in a wxGLCanvas created with the size of 100 (logical) pixels, the +rightmost physical pixel coordinate will be `100*GetContentScaleFactor()`. + + + +Platform-Specific Build Issues +============================== + +Generally speaking, all systems handle applications not specifically marked as +being "DPI-aware" by emulating low-resolution display for them and scaling them +up, resulting in blurry graphics and fonts, but globally preserving the +application appearance. For the best results, the application needs to be +explicitly marked as DPI-aware in a platform-dependent way. + +MSW +--- + +The behaviour of the application when running on a high-DPI display depends on +the values in its [manifest][1]. If your application include `wx/msw/wx.rc` +from its resource file, you need to predefine `wxUSE_DPI_AWARE_MANIFEST` to +opt-in into high DPI support: define it as `1` for minimal DPI awareness and +`2` for full, per-monitor DPI awareness supported by Windows 10 version 1703 or +later. + +[1]: https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests + + +macOS +----- + +DPI-aware applications must set their `NSPrincipalClass` to `wxNSApplication` +(or at least `NSApplication`) in their `Info.plist` file. Also see Apple [high +resolution guidelines][2] for more information. + +[2]: https://developer.apple.com/library/archive/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html From 7bf00e1161e5bf8f7a09892e10489fa85e56d699 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Mon, 21 Sep 2020 09:02:06 +0200 Subject: [PATCH 009/105] Added info about wxRB_SINGLE --- interface/wx/radiobut.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 0257bc31ce..3ae7778152 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -125,6 +125,8 @@ public: /** Returns the first radio button of the @c wxRB_GROUP this instance is in. + The return value is NULL if this button has the style @c wxRB_SINGLE. + @see GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() */ wxRadioButton* GetFirstInGroup(); @@ -132,6 +134,8 @@ public: /** Returns the last radio button of the @c wxRB_GROUP this instance is in. + The return value is NULL if this button has the style @c wxRB_SINGLE. + @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() */ wxRadioButton* GetLastInGroup(); @@ -139,6 +143,9 @@ public: /** Returns the previous radio button of the @c wxRB_GROUP this instance is in. + The return value is NULL if there is no predecessor or this button has + the style @c wxRB_SINGLE. + @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup() */ wxRadioButton* GetPreviousInGroup(); @@ -146,6 +153,9 @@ public: /** Returns the next radio button of the @c wxRB_GROUP this instance is in. + The return value is NULL if there is no successor or this button has + the style @c wxRB_SINGLE. + @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup() */ wxRadioButton* GetNextInGroup(); From 075d964eae41e947d233db39989ac37acae2a3d5 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Fri, 11 Sep 2020 15:11:36 +0300 Subject: [PATCH 010/105] Fix wxPropertyGrid string cropping detection (wxPG_TOOLTIPS) splitterHitOffset is only initialized when the mouse is near the splitter. --- src/propgrid/propgrid.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index 03921a9ce9..cd4f9ecdbd 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -5002,7 +5002,6 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, int splitterHit; int splitterHitOffset; int columnHit = state->HitTestH( x, &splitterHit, &splitterHitOffset ); - int splitterX = x - splitterHitOffset; m_colHover = columnHit; @@ -5012,6 +5011,7 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, x < (m_pState->GetVirtualWidth() - wxPG_DRAG_MARGIN) ) { + int splitterX = x - splitterHitOffset; int newSplitterX = x - m_dragOffset; // Splitter redraw required? @@ -5098,13 +5098,13 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, if ( m_mouseSide == 1 ) { tipString = m_propHover->GetLabel(); - space = splitterX-m_marginWidth-3; + space = m_pState->GetColumnWidth(0)-3; } else if ( m_mouseSide == 2 ) { tipString = m_propHover->GetDisplayedString(); - space = m_width - splitterX; + space = m_pState->GetColumnWidth(1); if ( m_propHover->HasFlag(wxPG_PROP_CUSTOMIMAGE) ) space -= wxPG_CUSTOM_IMAGE_WIDTH + wxCC_CUSTOM_IMAGE_MARGIN1 + From e4607a243ee7a2e780d6806dacb75ead2aa8c118 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Sat, 12 Sep 2020 18:44:56 +0300 Subject: [PATCH 011/105] Take subgroup margin into account when checking for property label cropping --- src/propgrid/propgrid.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index cd4f9ecdbd..ed60c9f7b8 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -5099,6 +5099,8 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, { tipString = m_propHover->GetLabel(); space = m_pState->GetColumnWidth(0)-3; + if ( !(m_windowStyle & wxPG_HIDE_CATEGORIES) || m_propHover->GetParent() != m_pState->DoGetRoot() ) + space -= (m_propHover->GetDepth()-1)*m_subgroup_extramargin; } else if ( m_mouseSide == 2 ) { From 7d83c6cfe06ac50d5bf1e09d9152952fd91c2bcb Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Sun, 13 Sep 2020 22:02:34 +0300 Subject: [PATCH 012/105] Take wxPG_XBEFORETEXT and splitter into account for cropping detection --- src/propgrid/propgrid.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index ed60c9f7b8..61302cc2bc 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -5098,7 +5098,7 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, if ( m_mouseSide == 1 ) { tipString = m_propHover->GetLabel(); - space = m_pState->GetColumnWidth(0)-3; + space = m_pState->GetColumnWidth(0); if ( !(m_windowStyle & wxPG_HIDE_CATEGORIES) || m_propHover->GetParent() != m_pState->DoGetRoot() ) space -= (m_propHover->GetDepth()-1)*m_subgroup_extramargin; } @@ -5115,6 +5115,7 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, if ( space ) { + space -= (wxPG_XBEFORETEXT + 1); int tw, th; GetTextExtent( tipString, &tw, &th, 0, 0 ); if ( tw > space ) From 47d8299c70fac844c67ff294d3ddb1b4fccbc357 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Tue, 15 Sep 2020 15:13:34 +0300 Subject: [PATCH 013/105] Make wxPG_TOOLTIPS work for >2 columns too --- include/wx/propgrid/propgrid.h | 7 +++-- src/propgrid/propgrid.cpp | 54 ++++++++++++---------------------- 2 files changed, 23 insertions(+), 38 deletions(-) diff --git a/include/wx/propgrid/propgrid.h b/include/wx/propgrid/propgrid.h index 7a34b8f4f1..6f2bff9894 100644 --- a/include/wx/propgrid/propgrid.h +++ b/include/wx/propgrid/propgrid.h @@ -1591,11 +1591,12 @@ protected: // 0 = not dragging, 1 = drag just started, 2 = drag in progress unsigned char m_dragStatus; +#if WXWIN_COMPATIBILITY_3_0 + // Unused variable. // 0 = margin, 1 = label, 2 = value. unsigned char m_mouseSide; // True when editor control is focused. -#if WXWIN_COMPATIBILITY_3_0 unsigned char m_editorFocused; #else bool m_editorFocused; @@ -1634,8 +1635,8 @@ protected: int m_clearThisMany; #endif - // Mouse is hovering over this column (index) - unsigned int m_colHover; + // Mouse is hovering over this column (index), -1 for margin + int m_colHover; // pointer to property that has mouse hovering wxPGProperty* m_propHover; diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index 61302cc2bc..87bc222a8b 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -355,7 +355,6 @@ void wxPropertyGrid::Init1() m_inOnValidationFailure = false; m_permanentValidationFailureBehavior = wxPG_VFB_DEFAULT; m_dragStatus = 0; - m_mouseSide = 16; m_editorFocused = false; // Set up default unspecified value 'colour' @@ -5003,6 +5002,10 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, int splitterHitOffset; int columnHit = state->HitTestH( x, &splitterHit, &splitterHitOffset ); + #if wxUSE_TOOLTIPS + wxPGProperty* prevHover = m_propHover; + int prevCol = m_colHover; + #endif m_colHover = columnHit; if ( m_dragStatus > 0 ) @@ -5042,10 +5045,6 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, int ih = m_lineHeight; int sy = y; - #if wxUSE_TOOLTIPS - wxPGProperty* prevHover = m_propHover; - unsigned char prevSide = m_mouseSide; - #endif int curPropHoverY = y - (y % ih); // On which item it hovers @@ -5064,20 +5063,13 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, } #if wxUSE_TOOLTIPS - // Store which side we are on - m_mouseSide = 0; - if ( columnHit == 1 ) - m_mouseSide = 2; - else if ( columnHit == 0 ) - m_mouseSide = 1; - // // If tooltips are enabled, show label or value as a tip // in case it doesn't otherwise show in full length. // if ( m_windowStyle & wxPG_TOOLTIPS ) { - if ( m_propHover != prevHover || prevSide != m_mouseSide ) + if ( m_propHover != prevHover || prevCol != m_colHover ) { if ( m_propHover && !m_propHover->IsCategory() ) { @@ -5089,43 +5081,35 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, SetToolTip(tipString); } - else + else if ( m_colHover >= 0 && m_colHover < (int)m_pState->GetColumnCount()) { // Show cropped value string as a tooltip wxString tipString; - int space = 0; + m_propHover->GetDisplayInfo(m_colHover, -1, 0, &tipString, (wxPGCell*)NULL); + int space = m_pState->GetColumnWidth(m_colHover); - if ( m_mouseSide == 1 ) + if ( m_colHover == 0 ) { - tipString = m_propHover->GetLabel(); - space = m_pState->GetColumnWidth(0); if ( !(m_windowStyle & wxPG_HIDE_CATEGORIES) || m_propHover->GetParent() != m_pState->DoGetRoot() ) space -= (m_propHover->GetDepth()-1)*m_subgroup_extramargin; } - else if ( m_mouseSide == 2 ) + else if ( m_colHover == 1 ) { - tipString = m_propHover->GetDisplayedString(); - - space = m_pState->GetColumnWidth(1); if ( m_propHover->HasFlag(wxPG_PROP_CUSTOMIMAGE) ) space -= wxPG_CUSTOM_IMAGE_WIDTH + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2; } - if ( space ) - { - space -= (wxPG_XBEFORETEXT + 1); - int tw, th; - GetTextExtent( tipString, &tw, &th, 0, 0 ); - if ( tw > space ) - SetToolTip( tipString ); - } - else - { - SetToolTip(wxEmptyString); - } - + space -= (wxPG_XBEFORETEXT + 1); + int tw, th; + GetTextExtent( tipString, &tw, &th, 0, 0 ); + if ( tw > space ) + SetToolTip( tipString ); + } + else + { + SetToolTip(wxEmptyString); } } else From 949cda937d63d14663846998de5644a29e365ff4 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Tue, 15 Sep 2020 16:38:34 +0300 Subject: [PATCH 014/105] Improve cropping detection for properties with images Take into account images in >2 columns and custom sized images --- src/propgrid/propgrid.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index 87bc222a8b..fc5a0f40ae 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -5088,19 +5088,29 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, m_propHover->GetDisplayInfo(m_colHover, -1, 0, &tipString, (wxPGCell*)NULL); int space = m_pState->GetColumnWidth(m_colHover); + int imageWidth = 0; + const wxBitmap& bmp = m_propHover->GetCell(m_colHover).GetBitmap(); + if ( bmp.IsOk() ) + { + imageWidth = bmp.GetWidth(); + int hMax = m_lineHeight - wxPG_CUSTOM_IMAGE_SPACINGY - 1; + if ( bmp.GetHeight() > hMax ) + imageWidth *= (double)hMax / bmp.GetHeight(); + } + if ( m_colHover == 0 ) { if ( !(m_windowStyle & wxPG_HIDE_CATEGORIES) || m_propHover->GetParent() != m_pState->DoGetRoot() ) space -= (m_propHover->GetDepth()-1)*m_subgroup_extramargin; } - else if ( m_colHover == 1 ) + else if ( m_colHover == 1 && !m_propHover->IsValueUnspecified()) { - if ( m_propHover->HasFlag(wxPG_PROP_CUSTOMIMAGE) ) - space -= wxPG_CUSTOM_IMAGE_WIDTH + - wxCC_CUSTOM_IMAGE_MARGIN1 + - wxCC_CUSTOM_IMAGE_MARGIN2; + wxSize imageSize = GetImageSize(m_propHover, -1); + if ( imageSize.x > 0 ) + imageWidth = imageSize.x; } + space -= m_propHover->GetImageOffset(imageWidth); space -= (wxPG_XBEFORETEXT + 1); int tw, th; GetTextExtent( tipString, &tw, &th, 0, 0 ); From 3d41fa1ac48c9a1ac6b1d681a063c0585d456b5c Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Tue, 15 Sep 2020 16:58:54 +0300 Subject: [PATCH 015/105] Fix cropping detection when wxPG_BOLD_MODIFIED is enabled --- src/propgrid/propgrid.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index fc5a0f40ae..310b0ac728 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -5113,7 +5113,10 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, space -= m_propHover->GetImageOffset(imageWidth); space -= (wxPG_XBEFORETEXT + 1); int tw, th; - GetTextExtent( tipString, &tw, &th, 0, 0 ); + wxFont* font = NULL; + if ( (m_windowStyle & wxPG_BOLD_MODIFIED) && m_propHover->HasFlag(wxPG_PROP_MODIFIED) ) + font = &m_captionFont; + GetTextExtent( tipString, &tw, &th, 0, 0, font ); if ( tw > space ) SetToolTip( tipString ); } From 4c11ab63c12f3d14f633f871e5c08a430dc95326 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Fri, 18 Sep 2020 13:42:31 +0300 Subject: [PATCH 016/105] Fix cropping detection for properties with choice item-specific images --- src/propgrid/propgrid.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index 310b0ac728..e41ac15c83 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -5085,11 +5085,13 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, { // Show cropped value string as a tooltip wxString tipString; - m_propHover->GetDisplayInfo(m_colHover, -1, 0, &tipString, (wxPGCell*)NULL); + wxPGCell cell; + int item = ( m_colHover == 1 ? m_propHover->GetChoiceSelection() : -1 ); + m_propHover->GetDisplayInfo(m_colHover, item, 0, &tipString, &cell); int space = m_pState->GetColumnWidth(m_colHover); int imageWidth = 0; - const wxBitmap& bmp = m_propHover->GetCell(m_colHover).GetBitmap(); + const wxBitmap& bmp = cell.GetBitmap(); if ( bmp.IsOk() ) { imageWidth = bmp.GetWidth(); @@ -5108,6 +5110,7 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxSize imageSize = GetImageSize(m_propHover, -1); if ( imageSize.x > 0 ) imageWidth = imageSize.x; + tipString = m_propHover->GetValueAsString(); } space -= m_propHover->GetImageOffset(imageWidth); From ca1e0862250e54c583ede5fa039e0ae0a7066aa0 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Fri, 18 Sep 2020 20:49:39 +0300 Subject: [PATCH 017/105] Show units in tooltips --- src/propgrid/propgrid.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index e41ac15c83..82865ae035 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -5111,6 +5111,12 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, if ( imageSize.x > 0 ) imageWidth = imageSize.x; tipString = m_propHover->GetValueAsString(); + if ( GetColumnCount() <= 2 ) + { + wxString unitsString = m_propHover->GetAttribute(wxPG_ATTR_UNITS, wxEmptyString); + if ( !unitsString.empty() ) + tipString = wxString::Format(wxS("%s %s"), tipString, unitsString ); + } } space -= m_propHover->GetImageOffset(imageWidth); From 2d8d1ad9d0dca5baa72d6852431c7c92699de4a7 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Fri, 18 Sep 2020 21:27:58 +0300 Subject: [PATCH 018/105] Fix cropping detection for cells with custom font --- src/propgrid/propgrid.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index 82865ae035..96405ffba6 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -5122,9 +5122,11 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, space -= m_propHover->GetImageOffset(imageWidth); space -= (wxPG_XBEFORETEXT + 1); int tw, th; - wxFont* font = NULL; + const wxFont* font = NULL; if ( (m_windowStyle & wxPG_BOLD_MODIFIED) && m_propHover->HasFlag(wxPG_PROP_MODIFIED) ) font = &m_captionFont; + if ( cell.GetFont().IsOk() ) + font = &cell.GetFont(); GetTextExtent( tipString, &tw, &th, 0, 0, font ); if ( tw > space ) SetToolTip( tipString ); From 42ec95ff929a5131f74a9aceabc163899888ec67 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 14:49:48 +0200 Subject: [PATCH 019/105] Add all Markdown headers to the table of contents This actually shows a ToC for the just added high DPI overview, which wasn't created before because the headers didn't have any anchors. --- docs/doxygen/Doxyfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 36bbbf3132..030a80bc3c 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -384,6 +384,7 @@ GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO +TOC_INCLUDE_HEADINGS = 3 #--------------------------------------------------------------------------- From dfd1638f39cd759697df4e28704b146a47dfe8fb Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:02:47 +0200 Subject: [PATCH 020/105] Improve radio button groups documentation Explain the role of wxRB_SINGLE better, it's useful not only for avoiding wxMSW bugs (which, besides, shouldn't exist any more). --- interface/wx/radiobut.h | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 3ae7778152..98407b1f38 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -12,20 +12,28 @@ mutually exclusive options. It has a text label next to a (usually) round button. - You can create a group of mutually-exclusive radio buttons by specifying - @c wxRB_GROUP for the first in the group. The group ends when another - radio button group is created, or there are no more radio buttons. You can navigate - among the items in a group with @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() + Radio buttons are typically used in groups of mutually-exclusive buttons, + i.e. exactly one of the buttons in the group is checked, and the other ones + are unchecked automatically. Such groups are created implicitly, but can + also be started explicitly by using @c wxRB_GROUP style: a button with this + style starts a new group and will become the initial selection in this + group. Alternatively, a radio button may be excluded from the group that it + would otherwise belong to by using @c wxRB_SINGLE style. + + To find the other elements of the same radio button group, you can use + GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() and + GetLastInGroup() functions. @beginStyleTable @style{wxRB_GROUP} Marks the beginning of a new group of radio buttons. @style{wxRB_SINGLE} - In some circumstances, radio buttons that are not consecutive - siblings trigger a hang bug in Windows (only). If this happens, add - this style to mark the button as not belonging to a group, and - implement the mutually-exclusive group behaviour yourself. + Creates a radio button which is not part of any radio button group. + When this style is used, no other radio buttons will be turned off + automatically when this button is turned on and such behaviour will + need to be implemented manually, in the event handler for this + button. @endStyleTable @beginEventEmissionTable{wxCommandEvent} From 3ccbee2e1c577ee75d0a2c74b7b926380dad7055 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:05:35 +0200 Subject: [PATCH 021/105] Mark radio button group navigation functions as new in 3.1.5 Just add the missing "@since" lines. --- interface/wx/radiobut.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 98407b1f38..2bf6b22261 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -136,6 +136,8 @@ public: The return value is NULL if this button has the style @c wxRB_SINGLE. @see GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() + + @since 3.1.5 */ wxRadioButton* GetFirstInGroup(); @@ -145,6 +147,8 @@ public: The return value is NULL if this button has the style @c wxRB_SINGLE. @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() + + @since 3.1.5 */ wxRadioButton* GetLastInGroup(); @@ -155,6 +159,8 @@ public: the style @c wxRB_SINGLE. @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup() + + @since 3.1.5 */ wxRadioButton* GetPreviousInGroup(); @@ -165,6 +171,8 @@ public: the style @c wxRB_SINGLE. @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup() + + @since 3.1.5 */ wxRadioButton* GetNextInGroup(); }; From 0edc9d7eda49e3bedd3af2e489a4998077b836a3 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:09:38 +0200 Subject: [PATCH 022/105] Just use wxPrivate namespace Writing "wxPrivate::wxFoo()" is a bit ugly, so just add a using directive for the namespace, it's not a problem to do it in this file. --- src/common/containr.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/common/containr.cpp b/src/common/containr.cpp index 9bcdbab781..0ab07916f1 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -353,6 +353,8 @@ wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) } // namespace wxPrivate +using namespace wxPrivate; + #endif // wxUSE_RADIOBTN // ---------------------------------------------------------------------------- @@ -473,7 +475,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // If we are in a radio button group, start from the first item in the // group if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) - winFocus = wxPrivate::wxGetFirstButtonInGroup((wxRadioButton*)winFocus); + winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); #endif // USE_RADIOBTN_NAV // ok, we found the focus - now is it our child? start_node = children.Find( winFocus ); @@ -569,7 +571,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) if ( child->HasFlag(wxRB_GROUP) ) { // need to tab into the active button within a group - wxRadioButton *rb = wxPrivate::wxGetSelectedButtonInGroup((wxRadioButton*)child); + wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child); if ( rb ) child = rb; } @@ -591,20 +593,20 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // find the correct radio button to focus if ( forward ) { - child = wxPrivate::wxGetNextButtonInGroup(lastBtn); + child = wxGetNextButtonInGroup(lastBtn); if ( !child ) { // no next button in group, set it to the first button - child = wxPrivate::wxGetFirstButtonInGroup(lastBtn); + child = wxGetFirstButtonInGroup(lastBtn); } } else { - child = wxPrivate::wxGetPreviousButtonInGroup(lastBtn); + child = wxGetPreviousButtonInGroup(lastBtn); if ( !child ) { // no previous button in group, set it to the last button - child = wxPrivate::wxGetLastButtonInGroup(lastBtn); + child = wxGetLastButtonInGroup(lastBtn); } } @@ -769,7 +771,7 @@ bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused) wxRadioButton* btn = wxDynamicCast(child, wxRadioButton); if (btn) { - wxRadioButton* selected = wxPrivate::wxGetSelectedButtonInGroup(btn); + wxRadioButton* selected = wxGetSelectedButtonInGroup(btn); if (selected) child = selected; } From fceaa907a80dc31e7b6ea107a844e0fd40a3d39b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:14:40 +0200 Subject: [PATCH 023/105] Remove CppUnit boilerplate from wxRadioButton unit test Replace CppUnit test case class with a simple fixture and use CHECK() instead of CPPUNIT_ASSERT_XXX(). No real changes. --- tests/controls/radiobuttontest.cpp | 83 +++++++++++------------------- 1 file changed, 31 insertions(+), 52 deletions(-) diff --git a/tests/controls/radiobuttontest.cpp b/tests/controls/radiobuttontest.cpp index a81d6aec61..ea0f2a93c8 100644 --- a/tests/controls/radiobuttontest.cpp +++ b/tests/controls/radiobuttontest.cpp @@ -27,40 +27,19 @@ #include "testableframe.h" #include "testwindow.h" -class RadioButtonTestCase : public CppUnit::TestCase +class RadioButtonTestCase { public: - RadioButtonTestCase() { } - - void setUp() wxOVERRIDE; - void tearDown() wxOVERRIDE; - -private: - CPPUNIT_TEST_SUITE( RadioButtonTestCase ); - WXUISIM_TEST( Click ); - CPPUNIT_TEST( Value ); - CPPUNIT_TEST( Group ); - CPPUNIT_TEST( Single ); - CPPUNIT_TEST_SUITE_END(); - - void Click(); - void Value(); - void Group(); - void Single(); + RadioButtonTestCase(); + ~RadioButtonTestCase(); +protected: wxRadioButton* m_radio; wxDECLARE_NO_COPY_CLASS(RadioButtonTestCase); }; -// register in the unnamed registry so that these tests are run by default -CPPUNIT_TEST_SUITE_REGISTRATION( RadioButtonTestCase ); - -// also include in its own registry so that these tests can be run alone -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RadioButtonTestCase, - "RadioButtonTestCase" ); - -void RadioButtonTestCase::setUp() +RadioButtonTestCase::RadioButtonTestCase() { m_radio = new wxRadioButton(wxTheApp->GetTopWindow(), wxID_ANY, "wxRadioButton"); @@ -68,12 +47,12 @@ void RadioButtonTestCase::setUp() m_radio->Refresh(); } -void RadioButtonTestCase::tearDown() +RadioButtonTestCase::~RadioButtonTestCase() { - wxDELETE(m_radio); + delete m_radio; } -void RadioButtonTestCase::Click() +TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Click", "[radiobutton]") { // OS X doesn't support selecting a single radio button #if wxUSE_UIACTIONSIMULATOR && !defined(__WXOSX__) @@ -87,28 +66,28 @@ void RadioButtonTestCase::Click() wxYield(); - CPPUNIT_ASSERT_EQUAL( 1, selected.GetCount() ); + CHECK(selected.GetCount() == 1); #endif } -void RadioButtonTestCase::Value() +TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Value", "[radiobutton]") { #ifndef __WXGTK__ EventCounter selected(m_radio, wxEVT_RADIOBUTTON); m_radio->SetValue(true); - CPPUNIT_ASSERT(m_radio->GetValue()); + CHECK(m_radio->GetValue()); m_radio->SetValue(false); - CPPUNIT_ASSERT(!m_radio->GetValue()); + CHECK(!m_radio->GetValue()); - CPPUNIT_ASSERT_EQUAL(0, selected.GetCount()); + CHECK(selected.GetCount() == 0); #endif } -void RadioButtonTestCase::Group() +TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") { wxWindow* const parent = wxTheApp->GetTopWindow(); @@ -133,31 +112,31 @@ void RadioButtonTestCase::Group() g1radio0->SetValue(true); g2radio0->SetValue(true); - CPPUNIT_ASSERT(g1radio0->GetValue()); - CPPUNIT_ASSERT(!g1radio1->GetValue()); - CPPUNIT_ASSERT(g2radio0->GetValue()); - CPPUNIT_ASSERT(!g2radio1->GetValue()); + CHECK(g1radio0->GetValue()); + CHECK(!g1radio1->GetValue()); + CHECK(g2radio0->GetValue()); + CHECK(!g2radio1->GetValue()); g1radio1->SetValue(true); g2radio1->SetValue(true); - CPPUNIT_ASSERT(!g1radio0->GetValue()); - CPPUNIT_ASSERT(g1radio1->GetValue()); - CPPUNIT_ASSERT(!g2radio0->GetValue()); - CPPUNIT_ASSERT(g2radio1->GetValue()); + CHECK(!g1radio0->GetValue()); + CHECK(g1radio1->GetValue()); + CHECK(!g2radio0->GetValue()); + CHECK(g2radio1->GetValue()); g2radio2->SetValue(true); - CPPUNIT_ASSERT(!g2radio0->GetValue()); - CPPUNIT_ASSERT(!g2radio1->GetValue()); - CPPUNIT_ASSERT(g2radio2->GetValue()); + CHECK(!g2radio0->GetValue()); + CHECK(!g2radio1->GetValue()); + CHECK(g2radio2->GetValue()); g1radio0->SetValue(true); g2radio0->SetValue(true); - CPPUNIT_ASSERT(g1radio0->GetValue()); - CPPUNIT_ASSERT(!g1radio1->GetValue()); - CPPUNIT_ASSERT(g2radio0->GetValue()); - CPPUNIT_ASSERT(!g2radio1->GetValue()); + CHECK(g1radio0->GetValue()); + CHECK(!g1radio1->GetValue()); + CHECK(g2radio0->GetValue()); + CHECK(!g2radio1->GetValue()); wxDELETE(g1radio0); wxDELETE(g1radio1); @@ -167,7 +146,7 @@ void RadioButtonTestCase::Group() wxDELETE(text); } -void RadioButtonTestCase::Single() +TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Single", "[radiobutton]") { //Create a group of 2 buttons, having second button selected wxScopedPtr gradio0(new wxRadioButton(wxTheApp->GetTopWindow(), @@ -199,7 +178,7 @@ void RadioButtonTestCase::Single() CHECK(ngradio->GetValue()); } -TEST_CASE("wxRadioButton::Focus", "[radiobutton][focus]") +TEST_CASE("RadioButton::Focus", "[radiobutton][focus]") { // Create a container panel just to be able to destroy all the windows // created here at once by simply destroying it. From 46a21e5abaa2d858a38e8fddbec442568806bb4f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:18:22 +0200 Subject: [PATCH 024/105] Use wxScopedPtr<> instead of manual delete in wxRadioButton test Make the test code safer and ensure that no controls created here remain alive after the test end. --- tests/controls/radiobuttontest.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/tests/controls/radiobuttontest.cpp b/tests/controls/radiobuttontest.cpp index ea0f2a93c8..583a9b64c4 100644 --- a/tests/controls/radiobuttontest.cpp +++ b/tests/controls/radiobuttontest.cpp @@ -23,6 +23,7 @@ #include "wx/stattext.h" #endif // WX_PRECOMP +#include "wx/scopedptr.h" #include "wx/uiaction.h" #include "testableframe.h" #include "testwindow.h" @@ -92,22 +93,22 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") wxWindow* const parent = wxTheApp->GetTopWindow(); // Create two different radio groups. - wxRadioButton* g1radio0 = new wxRadioButton(parent, wxID_ANY, "radio 1.0", + wxScopedPtr g1radio0(new wxRadioButton(parent, wxID_ANY, "radio 1.0", wxDefaultPosition, wxDefaultSize, - wxRB_GROUP); + wxRB_GROUP)); - wxRadioButton* g1radio1 = new wxRadioButton(parent, wxID_ANY, "radio 1.1"); + wxScopedPtr g1radio1(new wxRadioButton(parent, wxID_ANY, "radio 1.1")); - wxRadioButton* g2radio0 = new wxRadioButton(parent, wxID_ANY, "radio 2.0", + wxScopedPtr g2radio0(new wxRadioButton(parent, wxID_ANY, "radio 2.0", wxDefaultPosition, wxDefaultSize, - wxRB_GROUP); + wxRB_GROUP)); - wxRadioButton* g2radio1 = new wxRadioButton(parent, wxID_ANY, "radio 2.1"); + wxScopedPtr g2radio1(new wxRadioButton(parent, wxID_ANY, "radio 2.1")); // Check that having another control between radio buttons doesn't break // grouping. - wxStaticText* text = new wxStaticText(parent, wxID_ANY, "Label"); - wxRadioButton* g2radio2 = new wxRadioButton(parent, wxID_ANY, "radio 2.1"); + wxScopedPtr text(new wxStaticText(parent, wxID_ANY, "Label")); + wxScopedPtr g2radio2(new wxRadioButton(parent, wxID_ANY, "radio 2.1")); g1radio0->SetValue(true); g2radio0->SetValue(true); @@ -137,13 +138,6 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") CHECK(!g1radio1->GetValue()); CHECK(g2radio0->GetValue()); CHECK(!g2radio1->GetValue()); - - wxDELETE(g1radio0); - wxDELETE(g1radio1); - wxDELETE(g2radio0); - wxDELETE(g2radio1); - wxDELETE(g2radio2); - wxDELETE(text); } TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Single", "[radiobutton]") From 24cc6c541e06a6462bbbc482180950a545a33632 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:28:06 +0200 Subject: [PATCH 025/105] Don't DLL-export wxRadioButtonBase template class This is unnecessary, this class only has inline functions. --- include/wx/radiobut.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index 182ae9c8c5..d68ac4a665 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -43,7 +43,7 @@ namespace wxPrivate } // namespace wxPrivate template -class WXDLLIMPEXP_CORE wxRadioButtonBase : public W +class wxRadioButtonBase : public W { public: typedef W BaseWindowClass; From b5fb9bd8d63b96e97903118154ccc34c882827e4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:34:55 +0200 Subject: [PATCH 026/105] Compile radio button group navigation functions on all platforms Previously they were only used, and compiled, on the platforms without wxHAS_NATIVE_TAB_TRAVERSAL, i.e. were not compiled at all in wxGTK, but we now need them everywhere as they're used to implement public API. --- src/common/containr.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/common/containr.cpp b/src/common/containr.cpp index 0ab07916f1..93245b674d 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -233,9 +233,12 @@ void wxControlContainer::SetLastFocus(wxWindow *win) } } +#endif // !wxHAS_NATIVE_TAB_TRAVERSAL + // -------------------------------------------------------------------- // The following four functions are used to find other radio buttons -// within the same group. Used by wxSetFocusToChild +// within the same group. Used by wxSetFocusToChild() and to implement +// wxRadioButtonBase public API. // -------------------------------------------------------------------- #if wxUSE_RADIOBTN @@ -357,6 +360,8 @@ using namespace wxPrivate; #endif // wxUSE_RADIOBTN +#ifndef wxHAS_NATIVE_TAB_TRAVERSAL + // ---------------------------------------------------------------------------- // Keyboard handling - this is the place where the TAB traversal logic is // implemented. As this code is common to all ports, this ensures consistent From 1a4f628e405661c042dcaa5f62c076a9c328719e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:36:41 +0200 Subject: [PATCH 027/105] Make radio button navigation functions const This requires adding a couple of const_cast<>s in their implementation in order to still allow them returning non-const wxRadioButton pointers, but this seems preferable to not being able to call them on a const wxRadioButton in the first place. --- include/wx/radiobut.h | 24 ++++++++++++------------ interface/wx/radiobut.h | 8 ++++---- src/common/containr.cpp | 16 ++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index d68ac4a665..d999800efb 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -36,10 +36,10 @@ class WXDLLIMPEXP_FWD_CORE wxRadioButton; namespace wxPrivate { - WXDLLIMPEXP_CORE wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetNextButtonInGroup(const wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetPreviousButtonInGroup(const wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetFirstButtonInGroup(const wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn); } // namespace wxPrivate template @@ -50,24 +50,24 @@ public: wxRadioButtonBase() { } - wxRadioButton* GetFirstInGroup() + wxRadioButton* GetFirstInGroup() const { - return wxPrivate::wxGetFirstButtonInGroup( static_cast(this)); + return wxPrivate::wxGetFirstButtonInGroup(static_cast(this)); } - wxRadioButton* GetLastInGroup() + wxRadioButton* GetLastInGroup() const { - return wxPrivate::wxGetLastButtonInGroup( static_cast(this)); + return wxPrivate::wxGetLastButtonInGroup(static_cast(this)); } - wxRadioButton* GetPreviousInGroup() + wxRadioButton* GetPreviousInGroup() const { - return wxPrivate::wxGetPreviousButtonInGroup( static_cast(this)); + return wxPrivate::wxGetPreviousButtonInGroup(static_cast(this)); } - wxRadioButton* GetNextInGroup() + wxRadioButton* GetNextInGroup() const { - return wxPrivate::wxGetNextButtonInGroup( static_cast(this)); + return wxPrivate::wxGetNextButtonInGroup(static_cast(this)); } private: diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 2bf6b22261..9094b23fde 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -139,7 +139,7 @@ public: @since 3.1.5 */ - wxRadioButton* GetFirstInGroup(); + wxRadioButton* GetFirstInGroup() const; /** Returns the last radio button of the @c wxRB_GROUP this instance is in. @@ -150,7 +150,7 @@ public: @since 3.1.5 */ - wxRadioButton* GetLastInGroup(); + wxRadioButton* GetLastInGroup() const; /** Returns the previous radio button of the @c wxRB_GROUP this instance is in. @@ -162,7 +162,7 @@ public: @since 3.1.5 */ - wxRadioButton* GetPreviousInGroup(); + wxRadioButton* GetPreviousInGroup() const; /** Returns the next radio button of the @c wxRB_GROUP this instance is in. @@ -174,6 +174,6 @@ public: @since 3.1.5 */ - wxRadioButton* GetNextInGroup(); + wxRadioButton* GetNextInGroup() const; }; diff --git a/src/common/containr.cpp b/src/common/containr.cpp index 93245b674d..52b808a29f 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -246,7 +246,7 @@ void wxControlContainer::SetLastFocus(wxWindow *win) namespace wxPrivate { -wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetPreviousButtonInGroup(const wxRadioButton *btn) { if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) return NULL; @@ -276,7 +276,7 @@ wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) return prevBtn; } -wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetNextButtonInGroup(const wxRadioButton *btn) { if (btn->HasFlag(wxRB_SINGLE)) return NULL; @@ -306,35 +306,35 @@ wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn) return nextBtn; } -wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetFirstButtonInGroup(const wxRadioButton *btn) { while (true) { wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn); if (!prevBtn) - return btn; + return const_cast(btn); btn = prevBtn; } } -wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn) { while (true) { wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn); if (!nextBtn) - return btn; + return const_cast(btn); btn = nextBtn; } } -wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn) { // Find currently selected button if (btn->GetValue()) - return btn; + return const_cast(btn); if (btn->HasFlag(wxRB_SINGLE)) return NULL; From ee55427c286e6c54306d2417a90321b1931c9404 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:52:40 +0200 Subject: [PATCH 028/105] Make it simpler to write useful tests comparing windows Allow creating wxWindowPtr from wxScopedPtr<> too, to avoid having to use .get() in the test code, and add CHECK_SAME_WINDOW() macro which gives more useful information about the windows in case of failure. --- tests/testwindow.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/testwindow.h b/tests/testwindow.h index 64b455b261..00f8003ec5 100644 --- a/tests/testwindow.h +++ b/tests/testwindow.h @@ -9,6 +9,7 @@ #ifndef _WX_TESTS_TESTWINDOW_H_ #define _WX_TESTS_TESTWINDOW_H_ +#include "wx/scopedptr.h" #include "wx/window.h" // We need to wrap wxWindow* in a class as specializing StringMaker for @@ -17,6 +18,8 @@ class wxWindowPtr { public: explicit wxWindowPtr(wxWindow* win) : m_win(win) {} + template + explicit wxWindowPtr(const wxScopedPtr& win) : m_win(win.get()) {} wxString Dump() const { @@ -44,7 +47,9 @@ private: // Macro providing more information about the current focus if comparison // fails. -#define CHECK_FOCUS_IS(w) CHECK(wxWindowPtr(wxWindow::FindFocus()) == wxWindowPtr(w)) +#define CHECK_SAME_WINDOW(w1, w2) CHECK(wxWindowPtr(w1) == wxWindowPtr(w2)) + +#define CHECK_FOCUS_IS(w) CHECK_SAME_WINDOW(wxWindow::FindFocus(), w) namespace Catch { From b84bc8e26a84eb84cf8e13728560857e662f8348 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:44:59 +0200 Subject: [PATCH 029/105] Add unit tests for radio button group navigation functions Extend the existing "group" and "single" tests to check these functions too. This at least verifies that these functions can be used. --- tests/controls/radiobuttontest.cpp | 44 ++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/controls/radiobuttontest.cpp b/tests/controls/radiobuttontest.cpp index 583a9b64c4..cdcc144972 100644 --- a/tests/controls/radiobuttontest.cpp +++ b/tests/controls/radiobuttontest.cpp @@ -23,7 +23,6 @@ #include "wx/stattext.h" #endif // WX_PRECOMP -#include "wx/scopedptr.h" #include "wx/uiaction.h" #include "testableframe.h" #include "testwindow.h" @@ -108,7 +107,7 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") // Check that having another control between radio buttons doesn't break // grouping. wxScopedPtr text(new wxStaticText(parent, wxID_ANY, "Label")); - wxScopedPtr g2radio2(new wxRadioButton(parent, wxID_ANY, "radio 2.1")); + wxScopedPtr g2radio2(new wxRadioButton(parent, wxID_ANY, "radio 2.2")); g1radio0->SetValue(true); g2radio0->SetValue(true); @@ -138,6 +137,41 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") CHECK(!g1radio1->GetValue()); CHECK(g2radio0->GetValue()); CHECK(!g2radio1->GetValue()); + + + // Check that group navigation functions behave as expected. + + // GetFirstInGroup() + CHECK_SAME_WINDOW(g1radio0->GetFirstInGroup(), g1radio0); + CHECK_SAME_WINDOW(g1radio1->GetFirstInGroup(), g1radio0); + + CHECK_SAME_WINDOW(g2radio0->GetFirstInGroup(), g2radio0); + CHECK_SAME_WINDOW(g2radio1->GetFirstInGroup(), g2radio0); + CHECK_SAME_WINDOW(g2radio2->GetFirstInGroup(), g2radio0); + + // GetLastInGroup() + CHECK_SAME_WINDOW(g1radio0->GetLastInGroup(), g1radio1); + CHECK_SAME_WINDOW(g1radio1->GetLastInGroup(), g1radio1); + + CHECK_SAME_WINDOW(g2radio0->GetLastInGroup(), g2radio2); + CHECK_SAME_WINDOW(g2radio1->GetLastInGroup(), g2radio2); + CHECK_SAME_WINDOW(g2radio2->GetLastInGroup(), g2radio2); + + // GetNextInGroup() + CHECK_SAME_WINDOW(g1radio0->GetNextInGroup(), g1radio1); + CHECK_SAME_WINDOW(g1radio1->GetNextInGroup(), NULL); + + CHECK_SAME_WINDOW(g2radio0->GetNextInGroup(), g2radio1); + CHECK_SAME_WINDOW(g2radio1->GetNextInGroup(), g2radio2); + CHECK_SAME_WINDOW(g2radio2->GetNextInGroup(), NULL); + + // GetPreviousInGroup() + CHECK_SAME_WINDOW(g1radio0->GetPreviousInGroup(), NULL); + CHECK_SAME_WINDOW(g1radio1->GetPreviousInGroup(), g1radio0); + + CHECK_SAME_WINDOW(g2radio0->GetPreviousInGroup(), NULL); + CHECK_SAME_WINDOW(g2radio1->GetPreviousInGroup(), g2radio0); + CHECK_SAME_WINDOW(g2radio2->GetPreviousInGroup(), g2radio1); } TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Single", "[radiobutton]") @@ -170,6 +204,12 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Single", "[radiobutton]") CHECK(gradio1->GetValue()); CHECK(ngradio->GetValue()); + + // Also check that navigation works as expected with "single" buttons. + CHECK_SAME_WINDOW(sradio->GetFirstInGroup(), sradio); + CHECK_SAME_WINDOW(sradio->GetLastInGroup(), sradio); + CHECK_SAME_WINDOW(sradio->GetPreviousInGroup(), NULL); + CHECK_SAME_WINDOW(sradio->GetNextInGroup(), NULL); } TEST_CASE("RadioButton::Focus", "[radiobutton][focus]") From 9e51389676f389427d6fd73ad15c502fe64cc485 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 16:02:40 +0200 Subject: [PATCH 030/105] Improve radio button navigation functions documentation Correct the previously wrong described behaviour for wxRB_SINGLE buttons and also mention that Get{First,Last}InGroup() never return NULL. --- interface/wx/radiobut.h | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 9094b23fde..0a42c1c0f9 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -131,9 +131,16 @@ public: virtual void SetValue(bool value); /** - Returns the first radio button of the @c wxRB_GROUP this instance is in. + Returns the first button of the radio button group this button belongs + to. - The return value is NULL if this button has the style @c wxRB_SINGLE. + For a radio button with @c wxRB_SINGLE style, this function returns this + button itself, as it is the only member of its group. Otherwise, the + function returns the closest previous radio button with @c wxRB_GROUP + style (which could still be this button itself) or the first radio + button in the same window. + + The returned value is never @NULL. @see GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() @@ -142,21 +149,27 @@ public: wxRadioButton* GetFirstInGroup() const; /** - Returns the last radio button of the @c wxRB_GROUP this instance is in. + Returns the last button of the radio button group this button belongs + to. - The return value is NULL if this button has the style @c wxRB_SINGLE. + Similarly to GetFirstInGroup(), this function returns this button + itself if it has @c wxRB_SINGLE style. Otherwise, the function returns + the last button before the next button with @c wxRB_GROUP style or the + last radio button in the same window. - @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() + The returned value is never @NULL. + + @see GetPreviousInGroup(), GetNextInGroup() @since 3.1.5 */ wxRadioButton* GetLastInGroup() const; /** - Returns the previous radio button of the @c wxRB_GROUP this instance is in. + Returns the previous radio button in the same group. - The return value is NULL if there is no predecessor or this button has - the style @c wxRB_SINGLE. + The return value is @NULL if there is no predecessor or if this button + has @c wxRB_SINGLE style. @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup() @@ -165,10 +178,10 @@ public: wxRadioButton* GetPreviousInGroup() const; /** - Returns the next radio button of the @c wxRB_GROUP this instance is in. + Returns the next radio button in the same group. - The return value is NULL if there is no successor or this button has - the style @c wxRB_SINGLE. + The return value is @NULL if there is no successor or if this button + has @c wxRB_SINGLE style. @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup() From 3d72c009be9c062a4e828a1f50ed8240bab295fa Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 16:08:16 +0200 Subject: [PATCH 031/105] Add wxRadioButtonBase::{Set,Get}Value() Now that we do have wxRadioButtonBase class, declare wxRadioButton API methods as pure virtual in it, to force the derived classes to implement them. Also remove the outdated comment saying that there is no base class for wxRadioButtons in different ports, this is not true any longer. --- include/wx/gtk/radiobut.h | 4 ++-- include/wx/msw/radiobut.h | 4 ++-- include/wx/osx/radiobut.h | 4 ++-- include/wx/qt/radiobut.h | 4 ++-- include/wx/radiobut.h | 23 ++++++++--------------- include/wx/univ/radiobut.h | 4 ++++ 6 files changed, 20 insertions(+), 23 deletions(-) diff --git a/include/wx/gtk/radiobut.h b/include/wx/gtk/radiobut.h index b85f8ea723..785530a98e 100644 --- a/include/wx/gtk/radiobut.h +++ b/include/wx/gtk/radiobut.h @@ -39,8 +39,8 @@ public: const wxString& name = wxASCII_STR(wxRadioButtonNameStr) ); virtual void SetLabel(const wxString& label) wxOVERRIDE; - virtual void SetValue(bool val); - virtual bool GetValue() const; + virtual void SetValue(bool val) wxOVERRIDE; + virtual bool GetValue() const wxOVERRIDE; static wxVisualAttributes GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL); diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h index fc6d2a8949..41103ed3b9 100644 --- a/include/wx/msw/radiobut.h +++ b/include/wx/msw/radiobut.h @@ -43,8 +43,8 @@ public: const wxString& name = wxASCII_STR(wxRadioButtonNameStr)); // implement the radio button interface - virtual void SetValue(bool value); - virtual bool GetValue() const; + virtual void SetValue(bool value) wxOVERRIDE; + virtual bool GetValue() const wxOVERRIDE; // implementation only from now on virtual bool MSWCommand(WXUINT param, WXWORD id) wxOVERRIDE; diff --git a/include/wx/osx/radiobut.h b/include/wx/osx/radiobut.h index cf74f14d89..b6bcb8ada3 100644 --- a/include/wx/osx/radiobut.h +++ b/include/wx/osx/radiobut.h @@ -35,8 +35,8 @@ public: const wxValidator& validator = wxDefaultValidator, const wxString& name = wxASCII_STR(wxRadioButtonNameStr)); - virtual void SetValue(bool val); - virtual bool GetValue() const ; + virtual void SetValue(bool val) wxOVERRIDE; + virtual bool GetValue() const wxOVERRIDE; // implementation diff --git a/include/wx/qt/radiobut.h b/include/wx/qt/radiobut.h index 1502173105..da00d190cf 100644 --- a/include/wx/qt/radiobut.h +++ b/include/wx/qt/radiobut.h @@ -32,8 +32,8 @@ public: const wxValidator& validator = wxDefaultValidator, const wxString& name = wxASCII_STR(wxRadioButtonNameStr) ); - virtual void SetValue(bool value); - virtual bool GetValue() const; + virtual void SetValue(bool value) wxOVERRIDE; + virtual bool GetValue() const wxOVERRIDE; virtual QWidget *GetHandle() const wxOVERRIDE; diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index d999800efb..a4d78656bc 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -15,21 +15,6 @@ #if wxUSE_RADIOBTN -/* - There is no wxRadioButtonBase class as wxRadioButton interface is the same - as wxCheckBox(Base), but under some platforms wxRadioButton really - derives from wxCheckBox and on the others it doesn't. - - The pseudo-declaration of wxRadioButtonBase would look like this: - - class wxRadioButtonBase : public ... - { - public: - virtual void SetValue(bool value); - virtual bool GetValue() const; - }; - */ - #include "wx/control.h" class WXDLLIMPEXP_FWD_CORE wxRadioButton; @@ -42,6 +27,8 @@ namespace wxPrivate WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn); } // namespace wxPrivate +// Unlike most of the other wxXXXBase classes, this one needs to be a template +// as wxRadioButton derives from different classes in different ports. template class wxRadioButtonBase : public W { @@ -50,6 +37,12 @@ public: wxRadioButtonBase() { } + // Methods to be implemented by the derived classes: + virtual void SetValue(bool value) = 0; + virtual bool GetValue() const = 0; + + + // Methods implemented by this class itself. wxRadioButton* GetFirstInGroup() const { return wxPrivate::wxGetFirstButtonInGroup(static_cast(this)); diff --git a/include/wx/univ/radiobut.h b/include/wx/univ/radiobut.h index 0b6580a2ab..ab81a71c5a 100644 --- a/include/wx/univ/radiobut.h +++ b/include/wx/univ/radiobut.h @@ -46,6 +46,10 @@ public: const wxValidator& validator = wxDefaultValidator, const wxString& name = wxASCII_STR(wxRadioButtonNameStr)); + // (re)implement pure virtuals from wxRadioButtonBase + virtual void SetValue(bool value) wxOVERRIDE { return wxCheckBox::SetValue(value); } + virtual bool GetValue() const wxOVERRIDE { return wxCheckBox::GetValue(); } + // override some base class methods virtual void ChangeValue(bool value) wxOVERRIDE; From bcb016613e508aedde906a9f57cf2ac0cc8b25ba Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 17:59:22 +0200 Subject: [PATCH 032/105] Make wxRadioButtonBase a plain class, not template Use a dirty hack to accommodate wxUniv by deriving wxRadioButtonBase from wxCheckBox, rather than wxControl, there. This is not pretty, but should be addressed by refactoring wxUniv code and in the meanwhile all the other ports don't have to bother with using a template class unnecessarily. --- include/wx/gtk/radiobut.h | 2 +- include/wx/gtk1/radiobut.h | 2 +- include/wx/motif/radiobut.h | 2 +- include/wx/msw/radiobut.h | 2 +- include/wx/osx/radiobut.h | 2 +- include/wx/qt/radiobut.h | 2 +- include/wx/radiobut.h | 21 ++++++++++++++------- include/wx/univ/radiobut.h | 4 +--- 8 files changed, 21 insertions(+), 16 deletions(-) diff --git a/include/wx/gtk/radiobut.h b/include/wx/gtk/radiobut.h index 785530a98e..8a19a022dd 100644 --- a/include/wx/gtk/radiobut.h +++ b/include/wx/gtk/radiobut.h @@ -13,7 +13,7 @@ // wxRadioButton //----------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { public: wxRadioButton() { } diff --git a/include/wx/gtk1/radiobut.h b/include/wx/gtk1/radiobut.h index 662b681d74..d467f7100c 100644 --- a/include/wx/gtk1/radiobut.h +++ b/include/wx/gtk1/radiobut.h @@ -13,7 +13,7 @@ // wxRadioButton //----------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { public: wxRadioButton() { } diff --git a/include/wx/motif/radiobut.h b/include/wx/motif/radiobut.h index 5759f01162..0233364946 100644 --- a/include/wx/motif/radiobut.h +++ b/include/wx/motif/radiobut.h @@ -11,7 +11,7 @@ #ifndef _WX_RADIOBUT_H_ #define _WX_RADIOBUT_H_ -class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { wxDECLARE_DYNAMIC_CLASS(wxRadioButton); public: diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h index 41103ed3b9..765f6bcc8f 100644 --- a/include/wx/msw/radiobut.h +++ b/include/wx/msw/radiobut.h @@ -13,7 +13,7 @@ #include "wx/msw/ownerdrawnbutton.h" -class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase< wxMSWOwnerDrawnButton > +class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton { public: // ctors and creation functions diff --git a/include/wx/osx/radiobut.h b/include/wx/osx/radiobut.h index b6bcb8ada3..3934f839f8 100644 --- a/include/wx/osx/radiobut.h +++ b/include/wx/osx/radiobut.h @@ -11,7 +11,7 @@ #ifndef _WX_RADIOBUT_H_ #define _WX_RADIOBUT_H_ -class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { wxDECLARE_DYNAMIC_CLASS(wxRadioButton); diff --git a/include/wx/qt/radiobut.h b/include/wx/qt/radiobut.h index da00d190cf..145b97a4ea 100644 --- a/include/wx/qt/radiobut.h +++ b/include/wx/qt/radiobut.h @@ -10,7 +10,7 @@ class QRadioButton; -class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: wxRadioButton(); diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index a4d78656bc..90217847a5 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -27,14 +27,21 @@ namespace wxPrivate WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn); } // namespace wxPrivate -// Unlike most of the other wxXXXBase classes, this one needs to be a template -// as wxRadioButton derives from different classes in different ports. -template -class wxRadioButtonBase : public W +// TODO: In wxUniv, wxRadioButton must derive from wxCheckBox as it reuses +// much of its code. This should be fixed by refactoring wxCheckBox to allow +// this class to reuse its functionality without inheriting from it, but for +// now use this hack to allow the existing code to compile. +#ifdef __WXUNIVERSAL__ + #include "wx/checkbox.h" + + typedef wxCheckBox wxRadioButtonBaseBase; +#else + typedef wxControl wxRadioButtonBaseBase; +#endif + +class WXDLLIMPEXP_CORE wxRadioButtonBase : public wxRadioButtonBaseBase { public: - typedef W BaseWindowClass; - wxRadioButtonBase() { } // Methods to be implemented by the derived classes: @@ -64,7 +71,7 @@ public: } private: - wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxRadioButtonBase, W); + wxDECLARE_NO_COPY_CLASS(wxRadioButtonBase); }; extern WXDLLIMPEXP_DATA_CORE(const char) wxRadioButtonNameStr[]; diff --git a/include/wx/univ/radiobut.h b/include/wx/univ/radiobut.h index ab81a71c5a..711e0a676c 100644 --- a/include/wx/univ/radiobut.h +++ b/include/wx/univ/radiobut.h @@ -11,13 +11,11 @@ #ifndef _WX_UNIV_RADIOBUT_H_ #define _WX_UNIV_RADIOBUT_H_ -#include "wx/checkbox.h" - // ---------------------------------------------------------------------------- // wxRadioButton // ---------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: // constructors From 09060ed262ed283d2bd932625eb6a5a879f3cf92 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 18:01:47 +0200 Subject: [PATCH 033/105] Move radio group navigation functions to wxRadioButtonBase Now that this class is not a template any longer, we can have the code for radio button group navigation directly in it, without making it inline, so move the existing functions bodies into the new methods and remove the old functions entirely. No real changes, this is just a refactoring. --- include/wx/radiobut.h | 31 ++-------- src/common/containr.cpp | 112 ++++--------------------------------- src/common/radiobtncmn.cpp | 92 ++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 129 deletions(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index 90217847a5..f4cf3b1a09 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -19,14 +19,6 @@ class WXDLLIMPEXP_FWD_CORE wxRadioButton; -namespace wxPrivate -{ - WXDLLIMPEXP_CORE wxRadioButton* wxGetNextButtonInGroup(const wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetPreviousButtonInGroup(const wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetFirstButtonInGroup(const wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn); -} // namespace wxPrivate - // TODO: In wxUniv, wxRadioButton must derive from wxCheckBox as it reuses // much of its code. This should be fixed by refactoring wxCheckBox to allow // this class to reuse its functionality without inheriting from it, but for @@ -50,25 +42,10 @@ public: // Methods implemented by this class itself. - wxRadioButton* GetFirstInGroup() const - { - return wxPrivate::wxGetFirstButtonInGroup(static_cast(this)); - } - - wxRadioButton* GetLastInGroup() const - { - return wxPrivate::wxGetLastButtonInGroup(static_cast(this)); - } - - wxRadioButton* GetPreviousInGroup() const - { - return wxPrivate::wxGetPreviousButtonInGroup(static_cast(this)); - } - - wxRadioButton* GetNextInGroup() const - { - return wxPrivate::wxGetNextButtonInGroup(static_cast(this)); - } + wxRadioButton* GetFirstInGroup() const; + wxRadioButton* GetLastInGroup() const; + wxRadioButton* GetPreviousInGroup() const; + wxRadioButton* GetNextInGroup() const; private: wxDECLARE_NO_COPY_CLASS(wxRadioButtonBase); diff --git a/src/common/containr.cpp b/src/common/containr.cpp index 52b808a29f..d20098f869 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -233,103 +233,15 @@ void wxControlContainer::SetLastFocus(wxWindow *win) } } -#endif // !wxHAS_NATIVE_TAB_TRAVERSAL - // -------------------------------------------------------------------- -// The following four functions are used to find other radio buttons -// within the same group. Used by wxSetFocusToChild() and to implement -// wxRadioButtonBase public API. +// The following functions is used by wxSetFocusToChild() // -------------------------------------------------------------------- #if wxUSE_RADIOBTN -namespace wxPrivate +namespace { -wxRadioButton* wxGetPreviousButtonInGroup(const wxRadioButton *btn) -{ - if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) - return NULL; - - const wxWindowList& siblings = btn->GetParent()->GetChildren(); - wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); - wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") ); - - // Iterate over all previous siblings until we find the next radio button - wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious(); - wxRadioButton *prevBtn = 0; - while (nodeBefore) - { - prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton); - if (prevBtn) - break; - - nodeBefore = nodeBefore->GetPrevious(); - } - - if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE)) - { - // no more buttons in group - return NULL; - } - - return prevBtn; -} - -wxRadioButton* wxGetNextButtonInGroup(const wxRadioButton *btn) -{ - if (btn->HasFlag(wxRB_SINGLE)) - return NULL; - - const wxWindowList& siblings = btn->GetParent()->GetChildren(); - wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); - wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") ); - - // Iterate over all previous siblings until we find the next radio button - wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext(); - wxRadioButton *nextBtn = 0; - while (nodeNext) - { - nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton); - if (nextBtn) - break; - - nodeNext = nodeNext->GetNext(); - } - - if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) ) - { - // no more buttons or the first button of the next group - return NULL; - } - - return nextBtn; -} - -wxRadioButton* wxGetFirstButtonInGroup(const wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn); - if (!prevBtn) - return const_cast(btn); - - btn = prevBtn; - } -} - -wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn); - if (!nextBtn) - return const_cast(btn); - - btn = nextBtn; - } -} - wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn) { // Find currently selected button @@ -342,26 +254,22 @@ wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn) wxRadioButton *selBtn; // First check all previous buttons - for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn)) + for (selBtn = btn->GetPreviousInGroup(); selBtn; selBtn = selBtn->GetPreviousInGroup()) if (selBtn->GetValue()) return selBtn; // Now all following buttons - for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn)) + for (selBtn = btn->GetNextInGroup(); selBtn; selBtn = selBtn->GetNextInGroup()) if (selBtn->GetValue()) return selBtn; return NULL; } -} // namespace wxPrivate - -using namespace wxPrivate; +} // anonymous namespace #endif // wxUSE_RADIOBTN -#ifndef wxHAS_NATIVE_TAB_TRAVERSAL - // ---------------------------------------------------------------------------- // Keyboard handling - this is the place where the TAB traversal logic is // implemented. As this code is common to all ports, this ensures consistent @@ -480,7 +388,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // If we are in a radio button group, start from the first item in the // group if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) - winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); + winFocus = static_cast(winFocus)->GetFirstInGroup(); #endif // USE_RADIOBTN_NAV // ok, we found the focus - now is it our child? start_node = children.Find( winFocus ); @@ -598,20 +506,20 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // find the correct radio button to focus if ( forward ) { - child = wxGetNextButtonInGroup(lastBtn); + child = lastBtn->GetNextInGroup(); if ( !child ) { // no next button in group, set it to the first button - child = wxGetFirstButtonInGroup(lastBtn); + child = lastBtn->GetFirstInGroup(); } } else { - child = wxGetPreviousButtonInGroup(lastBtn); + child = lastBtn->GetPreviousInGroup(); if ( !child ) { // no previous button in group, set it to the last button - child = wxGetLastButtonInGroup(lastBtn); + child = lastBtn->GetLastInGroup(); } } diff --git a/src/common/radiobtncmn.cpp b/src/common/radiobtncmn.cpp index dc2bd09240..5e847c7ab9 100644 --- a/src/common/radiobtncmn.cpp +++ b/src/common/radiobtncmn.cpp @@ -92,4 +92,96 @@ wxCONSTRUCTOR_6( wxRadioButton, wxWindow*, Parent, wxWindowID, Id, \ wxString, Label, wxPoint, Position, wxSize, Size, long, WindowStyle ) +// ---------------------------------------------------------------------------- +// wxRadioButton group navigation +// ---------------------------------------------------------------------------- + +wxRadioButton* wxRadioButtonBase::GetFirstInGroup() const +{ + wxRadioButton* + btn = static_cast(const_cast(this)); + while (true) + { + wxRadioButton* prevBtn = btn->GetPreviousInGroup(); + if (!prevBtn) + return btn; + + btn = prevBtn; + } +} + +wxRadioButton* wxRadioButtonBase::GetLastInGroup() const +{ + wxRadioButton* + btn = static_cast(const_cast(this)); + while (true) + { + wxRadioButton* nextBtn = btn->GetNextInGroup(); + if (!nextBtn) + return btn; + + btn = nextBtn; + } +} + +wxRadioButton* wxRadioButtonBase::GetPreviousInGroup() const +{ + if ( HasFlag(wxRB_GROUP) || HasFlag(wxRB_SINGLE) ) + return NULL; + + const wxWindowList& siblings = GetParent()->GetChildren(); + wxWindowList::compatibility_iterator nodeThis = siblings.Find(this); + wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") ); + + // Iterate over all previous siblings until we find the next radio button + wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious(); + wxRadioButton *prevBtn = 0; + while (nodeBefore) + { + prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton); + if (prevBtn) + break; + + nodeBefore = nodeBefore->GetPrevious(); + } + + if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE)) + { + // no more buttons in group + return NULL; + } + + return prevBtn; +} + +wxRadioButton* wxRadioButtonBase::GetNextInGroup() const +{ + if ( HasFlag(wxRB_SINGLE) ) + return NULL; + + const wxWindowList& siblings = GetParent()->GetChildren(); + wxWindowList::compatibility_iterator nodeThis = siblings.Find(this); + wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") ); + + // Iterate over all previous siblings until we find the next radio button + wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext(); + wxRadioButton *nextBtn = 0; + while (nodeNext) + { + nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton); + if (nextBtn) + break; + + nodeNext = nodeNext->GetNext(); + } + + if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) ) + { + // no more buttons or the first button of the next group + return NULL; + } + + return nextBtn; +} + #endif // wxUSE_RADIOBTN From 808ff104dcfb8319e4a38f73923620f05c1415e4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 20:37:37 +0200 Subject: [PATCH 034/105] Don't compile wxGetSelectedButtonInGroup() if it's unused Now that this function is static, not using it results in warnings when building the ports not using it (e.g. wxX11). --- src/common/containr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/containr.cpp b/src/common/containr.cpp index d20098f869..cf5f630665 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -237,7 +237,7 @@ void wxControlContainer::SetLastFocus(wxWindow *win) // The following functions is used by wxSetFocusToChild() // -------------------------------------------------------------------- -#if wxUSE_RADIOBTN +#if defined(USE_RADIOBTN_NAV) namespace { @@ -268,7 +268,7 @@ wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn) } // anonymous namespace -#endif // wxUSE_RADIOBTN +#endif // USE_RADIOBTN_NAV // ---------------------------------------------------------------------------- // Keyboard handling - this is the place where the TAB traversal logic is From 8ae9987a29566970456c22f33e667ab30f51fe41 Mon Sep 17 00:00:00 2001 From: PB Date: Tue, 22 Sep 2020 18:59:41 +0200 Subject: [PATCH 035/105] Improve code examples in wxDataViewModel documentation Fix variable name for the model. Make the code using wxObjectDataPtr have the same flow as the code using a raw pointer. Format the code to be in accordance with the official guidelines. Closes #18924. --- interface/wx/dataview.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index f975b5c286..2abf7e778b 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -73,9 +73,10 @@ associating the model with a control like this: @code - wxDataViewCtrl *musicCtrl = new wxDataViewCtrl( this, wxID_ANY ); + wxDataViewCtrl *musicCtrl = new wxDataViewCtrl(this, wxID_ANY); wxDataViewModel *musicModel = new MyMusicModel; - m_musicCtrl->AssociateModel( musicModel ); + + musicCtrl->AssociateModel(musicModel); musicModel->DecRef(); // avoid memory leak !! // add columns now @@ -84,11 +85,10 @@ A potentially better way to avoid memory leaks is to use wxObjectDataPtr @code - wxObjectDataPtr musicModel; - - wxDataViewCtrl *musicCtrl = new wxDataViewCtrl( this, wxID_ANY ); - musicModel = new MyMusicModel; - m_musicCtrl->AssociateModel( musicModel.get() ); + wxDataViewCtrl *musicCtrl = new wxDataViewCtrl(this, wxID_ANY); + wxObjectDataPtr musicModel(new MyMusicModel); + + musicCtrl->AssociateModel(musicModel.get()); // add columns now @endcode From 6e8da8641cf1f3a0161111ff05f1200e5fd42f9a Mon Sep 17 00:00:00 2001 From: Eric Raijmakers Date: Wed, 23 Sep 2020 11:56:58 +0200 Subject: [PATCH 036/105] Add alpha blending for wxImage::Paste Add test cases for wxImage::Paste. Closes #12458. Co-Authored-By: Rachel Mark --- include/wx/image.h | 19 +- interface/wx/image.h | 26 +- src/common/image.cpp | 85 ++++- tests/image/image.cpp | 315 ++++++++++++++++++ tests/image/paste_input_background.png | Bin 0 -> 410 bytes ...erlay_transparent_border_opaque_square.png | Bin 0 -> 263 bytes ...nsparent_border_semitransparent_circle.png | Bin 0 -> 1632 bytes ...nsparent_border_semitransparent_square.png | Bin 0 -> 330 bytes ...ult_background_plus_circle_plus_square.png | Bin 0 -> 1220 bytes ...erlay_transparent_border_opaque_square.png | Bin 0 -> 265 bytes ...nsparent_border_semitransparent_square.png | Bin 0 -> 560 bytes ...esult_no_background_square_over_circle.png | Bin 0 -> 1648 bytes tests/testimage.h | 71 +++- 13 files changed, 490 insertions(+), 26 deletions(-) create mode 100644 tests/image/paste_input_background.png create mode 100644 tests/image/paste_input_overlay_transparent_border_opaque_square.png create mode 100644 tests/image/paste_input_overlay_transparent_border_semitransparent_circle.png create mode 100644 tests/image/paste_input_overlay_transparent_border_semitransparent_square.png create mode 100644 tests/image/paste_result_background_plus_circle_plus_square.png create mode 100644 tests/image/paste_result_background_plus_overlay_transparent_border_opaque_square.png create mode 100644 tests/image/paste_result_background_plus_overlay_transparent_border_semitransparent_square.png create mode 100644 tests/image/paste_result_no_background_square_over_circle.png diff --git a/include/wx/image.h b/include/wx/image.h index d53ff0b116..f73fa70fab 100644 --- a/include/wx/image.h +++ b/include/wx/image.h @@ -73,6 +73,16 @@ enum wxImageResizeQuality wxIMAGE_QUALITY_HIGH = 4 }; +// Constants for wxImage::Paste() for specifying alpha blending option. +enum wxImageAlphaBlendMode +{ + // Overwrite the original alpha values with the ones being pasted. + wxIMAGE_ALPHA_BLEND_OVER = 0, + + // Compose the original alpha values with the ones being pasted. + wxIMAGE_ALPHA_BLEND_COMPOSE = 1 +}; + // alpha channel values: fully transparent, default threshold separating // transparent pixels from opaque for a few functions dealing with alpha and // fully opaque @@ -348,9 +358,12 @@ public: wxImage Size( const wxSize& size, const wxPoint& pos, int r = -1, int g = -1, int b = -1 ) const; - // pastes image into this instance and takes care of - // the mask colour and out of bounds problems - void Paste( const wxImage &image, int x, int y ); + // Copy the data of the given image to the specified position of this one + // taking care of the out of bounds problems. Mask is respected, but alpha + // is simply replaced by default, use wxIMAGE_ALPHA_BLEND_COMPOSE to + // combine it with the original image alpha values if needed. + void Paste(const wxImage& image, int x, int y, + wxImageAlphaBlendMode alphaBlend = wxIMAGE_ALPHA_BLEND_OVER); // return the new image with size width*height wxImage Scale( int width, int height, diff --git a/interface/wx/image.h b/interface/wx/image.h index 57bee46b41..a2c5b25f98 100644 --- a/interface/wx/image.h +++ b/interface/wx/image.h @@ -60,6 +60,21 @@ enum wxImageResizeQuality wxIMAGE_QUALITY_HIGH }; + +/** + Constants for wxImage::Paste() for specifying alpha blending option. + + @since 3.2.0 +*/ +enum wxImageAlphaBlendMode +{ + /// Overwrite the original alpha values with the ones being pasted. + wxIMAGE_ALPHA_BLEND_OVER = 0, + + /// Compose the original alpha values with the ones being pasted. + wxIMAGE_ALPHA_BLEND_COMPOSE = 1 +}; + /** Possible values for PNG image type option. @@ -803,8 +818,17 @@ public: /** Copy the data of the given @a image to the specified position in this image. + + Takes care of the mask colour and out of bounds problems. + + @param alphaBlend + This parameter (new in wx 3.2.0) determines whether the alpha values + of the original image replace (default) or are composed with the + alpha channel of this image. Notice that alpha blending overrides + the mask handling. */ - void Paste(const wxImage& image, int x, int y); + void Paste(const wxImage& image, int x, int y, + wxImageAlphaBlendMode alphaBlend = wxIMAGE_ALPHA_BLEND_OVER); /** Replaces the colour specified by @e r1,g1,b1 by the colour @e r2,g2,b2. diff --git a/src/common/image.cpp b/src/common/image.cpp index 880c1c4ea7..8d935a1cfb 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -1608,7 +1608,9 @@ wxImage wxImage::Size( const wxSize& size, const wxPoint& pos, return image; } -void wxImage::Paste( const wxImage &image, int x, int y ) +void +wxImage::Paste(const wxImage & image, int x, int y, + wxImageAlphaBlendMode alphaBlend) { wxCHECK_RET( IsOk(), wxT("invalid image") ); wxCHECK_RET( image.IsOk(), wxT("invalid image") ); @@ -1639,15 +1641,18 @@ void wxImage::Paste( const wxImage &image, int x, int y ) if (width < 1) return; if (height < 1) return; + bool copiedPixels = false; + // If we can, copy the data using memcpy() as this is the fastest way. But - // for this the image being pasted must have "compatible" mask with this - // one meaning that either it must not have one at all or it must use the - // same masked colour. - if ( !image.HasMask() || + // for this we must not do alpha compositing and the image being pasted + // must have "compatible" mask with this one meaning that either it must + // not have one at all or it must use the same masked colour. + if (alphaBlend == wxIMAGE_ALPHA_BLEND_OVER && + (!image.HasMask() || ((HasMask() && (GetMaskRed()==image.GetMaskRed()) && (GetMaskGreen()==image.GetMaskGreen()) && - (GetMaskBlue()==image.GetMaskBlue()))) ) + (GetMaskBlue()==image.GetMaskBlue())))) ) { const unsigned char* source_data = image.GetData() + 3*(xx + yy*image.GetWidth()); int source_step = image.GetWidth()*3; @@ -1660,6 +1665,8 @@ void wxImage::Paste( const wxImage &image, int x, int y ) source_data += source_step; target_data += target_step; } + + copiedPixels = true; } // Copy over the alpha channel from the original image @@ -1668,21 +1675,69 @@ void wxImage::Paste( const wxImage &image, int x, int y ) if ( !HasAlpha() ) InitAlpha(); - const unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth(); - int source_step = image.GetWidth(); + const unsigned char* + alpha_source_data = image.GetAlpha() + xx + yy * image.GetWidth(); + const int source_step = image.GetWidth(); - unsigned char* target_data = GetAlpha() + (x+xx) + (y+yy)*M_IMGDATA->m_width; - int target_step = M_IMGDATA->m_width; + unsigned char* + alpha_target_data = GetAlpha() + (x + xx) + (y + yy) * M_IMGDATA->m_width; + const int target_step = M_IMGDATA->m_width; - for (int j = 0; j < height; j++, - source_data += source_step, - target_data += target_step) + switch (alphaBlend) { - memcpy( target_data, source_data, width ); + case wxIMAGE_ALPHA_BLEND_OVER: + { + // Copy just the alpha values. + for (int j = 0; j < height; j++, + alpha_source_data += source_step, + alpha_target_data += target_step) + { + memcpy(alpha_target_data, alpha_source_data, width); + } + break; + } + case wxIMAGE_ALPHA_BLEND_COMPOSE: + { + const unsigned char* + source_data = image.GetData() + 3 * (xx + yy * image.GetWidth()); + + unsigned char* + target_data = GetData() + 3 * ((x + xx) + (y + yy) * M_IMGDATA->m_width); + + // Combine the alpha values but also apply alpha blending to + // the pixels themselves while we copy them. + for (int j = 0; j < height; j++, + alpha_source_data += source_step, + alpha_target_data += target_step, + source_data += 3 * source_step, + target_data += 3 * target_step) + { + for (int i = 0; i < width; i++) + { + float source_alpha = alpha_source_data[i] / 255.0f; + float light_left = (alpha_target_data[i] / 255.0f) * (1.0f - source_alpha); + float result_alpha = source_alpha + light_left; + alpha_target_data[i] = (unsigned char)((result_alpha * 255) +0.5); + for (int c = 3 * i; c < 3 * (i + 1); c++) + { + target_data[c] = + (unsigned char)(((source_data[c] * source_alpha + + target_data[c] * light_left) / + result_alpha) + 0.5); + } + } + } + + copiedPixels = true; + break; + } } + } - if (!HasMask() && image.HasMask()) + // If we hadn't copied them yet we must need to take the mask of the image + // being pasted into account. + if (!copiedPixels) { unsigned char r = image.GetMaskRed(); unsigned char g = image.GetMaskGreen(); diff --git a/tests/image/image.cpp b/tests/image/image.cpp index f76e79162c..aa67d7678f 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -1454,6 +1454,321 @@ void ImageTestCase::ScaleCompare() #endif //wxUSE_IMAGE +TEST_CASE("wxImage::Paste", "[image][paste]") +{ + const static char* squares_xpm[] = + { + "9 9 7 1", + " c None", + "y c #FF0000", + "r c #FF0000", + "g c #00FF00", + "b c #0000FF", + "o c #FF6600", + "w c #FFFFFF", + "rrrrwgggg", + "rrrrwgggg", + "rrrrwgggg", + "rrrrwgggg", + "wwwwwwwww", + "bbbbwoooo", + "bbbbwoooo", + "bbbbwoooo", + "bbbbwoooo" + }; + + const static char* toggle_equal_size_xpm[] = + { + "9 9 2 1", + " c None", + "y c #FF0000", + "y y y y y", + " y y y y ", + "y y y y y", + " y y y y ", + "y y y y y", + " y y y y ", + "y y y y y", + " y y y y ", + "y y y y y", + }; + + SECTION("Paste same size image") + { + wxImage actual(squares_xpm); + wxImage paste(toggle_equal_size_xpm); + wxImage expected(toggle_equal_size_xpm); + actual.Paste(paste, 0, 0); + CHECK_THAT(actual, RGBSameAs(expected)); + } + + SECTION("Paste larger image") + { + const static char* toggle_larger_size_xpm[] = + { + "13 13 2 1", + " c None", + "y c #FF0000", + "y y y y y y y", + " y y y y y y ", + "y y y y y y y", + " y y y y y y ", + "y y y y y y y", + " y y y y y y ", + "y y y y y y y", + " y y y y y y ", + "y y y y y y y", + " y y y y y y ", + "y y y y y y y", + " y y y y y y ", + "y y y y y y y", + }; + + wxImage actual(squares_xpm); + wxImage paste(toggle_larger_size_xpm); + wxImage expected(toggle_equal_size_xpm); + actual.Paste(paste, -2, -2); + CHECK_THAT(actual, RGBSameAs(expected)); + } + + SECTION("Paste smaller image") + { + const static char* toggle_smaller_size_xpm[] = + { + "5 5 2 1", + " c None", + "y c #FF0000", + "y y y", + " y y ", + "y y y", + " y y ", + "y y y", + }; + + const static char* expected_xpm[] = + { + "9 9 7 1", + " c None", + "y c #FF0000", + "r c #FF0000", + "g c #00FF00", + "b c #0000FF", + "o c #FF6600", + "w c #FFFFFF", + "rrrrwgggg", + "rrrrwgggg", + "rry y ygg", + "rr y y gg", + "wwy y yww", + "bb y y oo", + "bby y yoo", + "bbbbwoooo", + "bbbbwoooo" + }; + + wxImage actual(squares_xpm); + wxImage paste(toggle_smaller_size_xpm); + wxImage expected(expected_xpm); + actual.Paste(paste, 2, 2); + CHECK_THAT(actual, RGBSameAs(expected)); + } + + SECTION("Paste beyond top left corner") + { + const static char* expected_xpm[] = + { + "9 9 7 1", + " c None", + "y c #FF0000", + "r c #FF0000", + "g c #00FF00", + "b c #0000FF", + "o c #FF6600", + "w c #FFFFFF", + "oooowgggg", + "oooowgggg", + "oooowgggg", + "oooowgggg", + "wwwwwwwww", + "bbbbwoooo", + "bbbbwoooo", + "bbbbwoooo", + "bbbbwoooo" + }; + + wxImage actual(squares_xpm); + wxImage paste(squares_xpm); + wxImage expected(expected_xpm); + actual.Paste(paste, -5, -5); + CHECK_THAT(actual, RGBSameAs(expected)); + } + + SECTION("Paste beyond top right corner") + { + const static char* expected_xpm[] = + { + "9 9 7 1", + " c None", + "y c #FF0000", + "r c #FF0000", + "g c #00FF00", + "b c #0000FF", + "o c #FF6600", + "w c #FFFFFF", + "rrrrwbbbb", + "rrrrwbbbb", + "rrrrwbbbb", + "rrrrwbbbb", + "wwwwwwwww", + "bbbbwoooo", + "bbbbwoooo", + "bbbbwoooo", + "bbbbwoooo" + }; + wxImage actual(squares_xpm); + wxImage paste(squares_xpm); + wxImage expected(expected_xpm); + actual.Paste(paste, 5, -5); + CHECK_THAT(actual, RGBSameAs(expected)); + } + + SECTION("Paste beyond bottom right corner") + { + const static char* expected_xpm[] = + { + "9 9 7 1", + " c None", + "y c #FF0000", + "r c #FF0000", + "g c #00FF00", + "b c #0000FF", + "o c #FF6600", + "w c #FFFFFF", + "rrrrwgggg", + "rrrrwgggg", + "rrrrwgggg", + "rrrrwgggg", + "wwwwwwwww", + "bbbbwrrrr", + "bbbbwrrrr", + "bbbbwrrrr", + "bbbbwrrrr" + }; + wxImage actual(squares_xpm); + wxImage paste(squares_xpm); + wxImage expected(expected_xpm); + actual.Paste(paste, 5, 5); + CHECK_THAT(actual, RGBSameAs(expected)); + } + + SECTION("Paste beyond bottom left corner") + { + const static char* expected_xpm[] = + { + "9 9 7 1", + " c None", + "y c #FF0000", + "r c #FF0000", + "g c #00FF00", + "b c #0000FF", + "o c #FF6600", + "w c #FFFFFF", + "rrrrwgggg", + "rrrrwgggg", + "rrrrwgggg", + "rrrrwgggg", + "wwwwwwwww", + "ggggwoooo", + "ggggwoooo", + "ggggwoooo", + "ggggwoooo" + }; + wxImage actual(squares_xpm); + wxImage paste(squares_xpm); + wxImage expected(expected_xpm); + actual.Paste(paste, -5, 5); + CHECK_THAT(actual, RGBSameAs(expected)); + } + + wxImage::AddHandler(new wxPNGHandler()); + wxImage background("image/paste_input_background.png"); + CHECK(background.IsOk()); + wxImage opaque_square("image/paste_input_overlay_transparent_border_opaque_square.png"); + CHECK(opaque_square.IsOk()); + wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png"); + CHECK(transparent_square.IsOk()); + wxImage transparent_circle("image/paste_input_overlay_transparent_border_semitransparent_circle.png"); + CHECK(transparent_circle.IsOk()); + + SECTION("Paste fully opaque image onto blank image without alpha") + { + wxImage actual(background.GetSize()); + actual.Paste(background, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSameAs(background)); + CHECK(!actual.HasAlpha()); + } + SECTION("Paste fully opaque image onto blank image with alpha") + { + wxImage actual(background.GetSize()); + actual.InitAlpha(); + actual.Paste(background, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSameAs(background)); + CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE)); + } + SECTION("Paste fully transparent image") + { + wxImage actual = background.Copy(); + wxImage transparent(actual.GetSize()); + transparent.InitAlpha(); + memset(transparent.GetAlpha(), 0, transparent.GetWidth() * transparent.GetHeight()); + actual.Paste(transparent, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSameAs(background)); + CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE)); + } + SECTION("Paste image with transparent region") + { + wxImage actual = background.Copy(); + actual.Paste(opaque_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSameAs(wxImage("image/paste_result_background_plus_overlay_transparent_border_opaque_square.png"))); + CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE)); + } + SECTION("Paste image with semi transparent region") + { + wxImage actual = background.Copy(); + actual.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSameAs(wxImage("image/paste_result_background_plus_overlay_transparent_border_semitransparent_square.png"))); + CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE)); + } + SECTION("Paste two semi transparent images on top of background") + { + wxImage actual = background.Copy(); + actual.Paste(transparent_circle, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + actual.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSimilarTo(wxImage("image/paste_result_background_plus_circle_plus_square.png"), 1)); + CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE)); + } + SECTION("Paste two semi transparent images together first, then on top of background") + { + wxImage circle = transparent_circle.Copy(); + wxImage actual = background.Copy(); + circle.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + actual.Paste(circle, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + // When applied in this order, two times a rounding difference is triggered. + CHECK_THAT(actual, RGBSimilarTo(wxImage("image/paste_result_background_plus_circle_plus_square.png"), 2)); + CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE)); + } + SECTION("Paste semitransparent image over transparent image") + { + wxImage actual(transparent_circle.GetSize()); + actual.InitAlpha(); + memset(actual.GetAlpha(), 0, actual.GetWidth() * actual.GetHeight()); + actual.Paste(transparent_circle, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, CenterAlphaPixelEquals(192)); + actual.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSimilarTo(wxImage("image/paste_result_no_background_square_over_circle.png"), 1)); + CHECK_THAT(actual, CenterAlphaPixelEquals(224)); + } +} /* TODO: add lots of more tests to wxImage functions diff --git a/tests/image/paste_input_background.png b/tests/image/paste_input_background.png new file mode 100644 index 0000000000000000000000000000000000000000..fd93b550ce660b5fbb5507e9ea1757415cb2236e GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^DIm!lvI6;>0X`wF46^?l8XErpXP6lg^8_SV;1OBOz`%D1gc(IOyc&R}NO`(AhD02G zJN>la5d|J+XZAv?h+q0epXCjVZrpnONO{%^U!e_0jk2%lY+})0eziu4^O{Qz$F)f( zvYd>rr2LMMxM_5$YA6( zTgo)!`@|^YX;Wi653Y{gFUKPNP4U7;e#dFb93NyHqb?gRDU@~IvX*^OjqQY6H`rGi z*m?ARboA;G4occHLFjSImKlai4)!QYJ#N(KVGl~KnZWh9xnlc=evwD9kK%iN=zrYr z|7PP4Kecn-e?o-P?e8Ua*onQL=HlO1UYE4*$Z`oo?Z?71XZ-$H;+P_#q$yb0<5BCf zEk#IY;^dhoekpa&(j4!^&xjT(6rXMSx;`s%-#qUw*9Gn~*nmOD;OXk;vd$@?2>>K( Bp>F^H literal 0 HcmV?d00001 diff --git a/tests/image/paste_input_overlay_transparent_border_opaque_square.png b/tests/image/paste_input_overlay_transparent_border_opaque_square.png new file mode 100644 index 0000000000000000000000000000000000000000..fa32073e5c9dce4557a83df8ce75d477b426ec60 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^DImNS%G|>0G|+7ApKvKf#*MvW>DKFaRErNlmz(&|NsA=!9i=~7a*Urz$3Dlfr0N3 z2s4Umcr^e8OFUg1Lo%G-p54gXY{0;9P~iQ3<6ds@hA#q39m<*i)E|?dp`zC5nKTJV zoxGS*ofamhCZ3jBX!i47GDr+6g^kMnbYP8+kKUP6k1{?L!xWy3R!e@<{U?bbuXzza P(0&F_S3j3^P6Px#1ZP1_K>z@;j|==^1poj532;bRa{vGibN~PjbOCE5v(^9r1@%cpK~#8N?VU|% zTvZgu&&woDw6T6Q)J2dkQrbnJfw~ZJ5g`;8MY5>Sg$qR&Qbk*+QbY)%6kSz8OTmR8 zT?i_;$V#$!%OZkBx@a-0Qc#H?)Co}iseV!kLmv?6|@1Fmhd(QoQ z#4rrQFbu;m48t%C!!QivLSn9!LVWQ;O21ztTK+>9-1?1Z?KaWi2+^L$bQ!K=6O_Dk zX<8RlgGvY@&P}Cs^NP9iV0?;_cdnFLpi&AVzCM-G)p??&MN=Xf7$n;LsPuwi=^0Bz zcmFjXbYbW|qR}y;^;PXn8*AnR$s_xT4$o5Z{Kusds8oV4!_YDH)KSupxiBMbZBKM@~@k@>hijQ-~m9elDf&Khl{IVnb_}Y(oAqpB4z3NHk~a z2O^*A=vhjh`yf|gau-BgoK5NH@8mZR=;kS8d;d1B8Yf> zFjejH$b+(p`pcA72&BqrT9XzfpRGp~CAuKuB&F(~q5I1bxC4+}plG5*6(sYFx)IS+ zWU3Pf6*C|PJfm)ibrPpXwdV&WiXbYRLI6k1s7W)m1;iAYn25QF;GzTkE2xIuJpFx_DzGRYTqA;Wh<~ zILN=`)3qQ$KA4B7fkO0Z(Nr}F)K?}i;`8G{yd+$cg;84!$dz$yDki8e>iyFXfK}*BC&n(Bo%+DdL$Fx}^s*(OiCDWhq`z*0 z*quvEcd)aoPyAvC6C5`|9F%V)xp_zx7D|@^2Rpe5g4Gtx&N$e~O%S{FnCXs#oj9nM z3^zeW_nLp0uH@z+`wrWbGscK;ZH zUOS7S!BSF(-g!Gg_82NJDf+ytqA~UNJ>|jQL%;#~3=pHKV_T><>c9U4b>-y~39)O+%nDexnhhX8fh4ECt=K6Pipc?dXqR*TV; zId{Yk)c2`ZOo2Z^Jp^P&zS@)6>WZzO4CKk%mxFi*2rdXvr{rK6WnBjzZM_~Er{vtt zU}AtMf&g`%RGmAF!*R}Fj3x*WueD^5UpIGk0VWecQrztb8`SS1_JNW4qs5?S-_^Gf zh$;wBzoew4Z_xHuk?gs(7%@+~j@o3klf{&(WncDrBgKq+iS8j5RT+$g+LPF-0Qwnt zUSv}_hyijF1gPV>56@O)3d8nn~b3%SLR?NGfvMoSe^92uq=YSky^u_V6!E z2N(5*oxsB&E|fwLOJVPz%JFp+J5ee@Ec}+XlGEWiuJC&d<51@}eKHKgFbu;m48t%C e!!S%WAo>p+&e_F!fJ0000}0^zU(`1 zbZ3Gur;xHokAh*-5e~XC9e2RbGnNRK)Y;dCG|;6O^)foQh_Nr4Rw4F_Vq z4rIh0C@DG+<8dI`{XlX4fyVX&5zYr{8yjTn5BNF!?_>CoWdFfk_<@!D11rS`Hp(B| z1wSO({ZE(s;3n|FQ}lzU$o~|{|M3F(+*Tr{EuM%5NrNFN%VgVSL-9a+@lHwK#$m$1o;L3 zrwlAsnLG<<6lZ})WHAE+UkL~^W~*$z1`M`fPZ!6KjK;S&Bf}pVh%h{G;@l)IdW13c zqLv$**NVlDjsE?gpQ@J|c}Z<&>m+0Tz4`@ylk3zoCoMCdHq~9O^2tPZwm^+rWt~%U zcE?!o7PuX;I4!m!|&5!=t zg}5qbCl|cm#UI7==wj*eW{-nPjUQd+$6j}p*mK2rt}B-iXV3i-KTWrXsT#2tDpx!Z zFtEu#8P?PO{!WMDh&Jle=HfJ12Qqqv_y{CO^Zw zN2f~Ly^?h6l65y`HEW&-|^So zUXvbv{+j3_aE$fg>vgkB+HF-Ye)uV6!go*qm4avpaBqVA+MCwf=x_6WQ=;g;Q`6(@Q*R%*_6dd1WfQ1(2d zQ`yTkV)kNo|5HUr{9Hu3cKpj1 zur^f+P0Bao37VuJr222$9R*cOr<9Jgr~S%Z4^x+@y3OmHcri6)p2Ww-`mX zMrR#4@>^xK`QobQsgGpy)3zt2Z+ai(zSJQ5qB5w z-y+iec$+5MKFPJ&Cnjd{-n{<)@dw%F2w~>?AJ5$tlJH`9SxVvmr&@)}&$Zg)w_!Qo{7iq@Yl3nedj!w?JX!tg^W?Qm`(xjF z22^gZ$Wr~Y*zWSGuA}_Dm*<}2Ec{e_OvA4(X%;9yeEffezm4fOb3-ZrT40`I@O1Ta JS?83{1ONcPPA&id literal 0 HcmV?d00001 diff --git a/tests/image/paste_result_background_plus_overlay_transparent_border_opaque_square.png b/tests/image/paste_result_background_plus_overlay_transparent_border_opaque_square.png new file mode 100644 index 0000000000000000000000000000000000000000..60da07730df542040281e9c86dd657cc9bf3fda2 GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^DImXiIvio%aD9%z6fMT2l9+AZi416UZ z%$TjR`5FTQ<7`hC$B>N1w=?f{|v`qQ3^iAS>4IgUHVClI0 zq-bZ1-u1;?4?REkPd<4zqs~I|PS3N;Cizj*Qe(Hzm%MyartOWN#Zm)z#eDTCL9?1C ztQU4$dB)JAtV@3Bl(=1H-Rn!2IrL2UAJL+j?slfwF-fPz=4VF`m)jX_HkVIgZ?icA zHC2_J!xZAJ1X_a(13Y%ea4k(+aQf<=iq=a855(hJH#lWVR&cyO8BtxXA?tQzvf=ZB z*YUwsJt-R6(o4;q9A6quTIz7FxW1?4pvSTxd+)_BdZr653ObS=*5Nd9{tU%O5vOF{ z3S^q3%Caj6xu)_B;JN9;ZVSjpwio{+~ujw6^-Y+V7XJPB%XFm0^__LB7mV2uX tg}2B0*V|j(nP+T&XP!wpD5UpalIINYOVU&*Jpqh622WQ%mvv4FO#rlR?5F?$ literal 0 HcmV?d00001 diff --git a/tests/image/paste_result_no_background_square_over_circle.png b/tests/image/paste_result_no_background_square_over_circle.png new file mode 100644 index 0000000000000000000000000000000000000000..d27564a130f7ed7dddf49dc84da24cb9fafd2b71 GIT binary patch literal 1648 zcmV-$29NoPP)Pe>g{9LK-&_C5c^V5m_{i$+NlEDBnpkV7GR$T5c;Qph3j zQgRS_N}=S?OG^)-&_kM|0|yQR`DS42CE&i^-%z0yXzK#}9nqWoa`d;3eqi)0*cU(By8Txn zQG&eF6AG<>RRFd(^;Oc+4tVaHf_4vqefPxHSBX4{5QJYp?cnJ>@k`S|036uaGGB31 zo4AH`4ccH|JGS|XKTKT(;kPb2crY!#N^%9jckAcO?)p!h2fK9Ju7?|11@U|FeN~m( z6GbdP1bh!*49Ho4SKhy%X)FuyeSmY}*U@qC*|}0RMRP0FwS8YZI*il;8$VXW-*W)> zfP6tTJ_%v~faeK+tO5WIJf8#mthX4a3$Y5qhC7N_|4Z};4xn7euc*E7T;X5N0{&Y8 z`}9z3qQoW$8*C|J>tFHT=X-HgtA_6he_wBa9WTTpO5UXL_UGa{d7l-*w*jjO@ODgA zX#iJ<;<*4=aq1K=0l;RTnc9r^kjYsT!MT{&HJlg$Uij6@MSBclRFKL0EOOpY$iS_E z$ysJh6k~$0!Ir3Jqz-OuOfez|8}2B=4aSTV^^6L^m}27YOS>R!{8)51)u>~}et2$l z_oaEBqE!%PPek(!FQIb`U3hLZPx*XQn<#pF$nrz+Fs4!F8LIf6XzxFZ+DvK_gx|X8 zR3=hc!V-^v_>FUp4s-f?$b)I|KrX3|LrhV2MZ4$kYB8rp5Pto%BOak!I?Od5LA&`i z+fg>9Y5)N6^qyExNXk>&xbcGZoIf39Q_6zyt7F28dM+*{fuQ}Bcu1n&Lsl1pWmf`C zZBX4Eqa+BwbJ+=gQgR|~@VnnQvSrnJ$fFr?jblSXBM`=6@fT?mYJ#jUiLE+BM4|P~ z{bV(wK89p%BDf!l@sJjzayOxK6I&Vx;=z9$cVvpo_mI_vl&*DXAeRT0f0rw&RPlks zO2t!)LR{1Y$u}z%Pb~^@krIU8yx;&3yU>Yu3F1mx#UDd{J|e*!T7ldm|@^gz}jrwjNU6mMWGxB;q6|NWMj?Smuz3lbj&o(PLt7 zB;rJadcu$s}H&RM$J*0a`Txl)j{e*Gp8mPIblpvLK6>VKI#nVp^7n!skYGa6> z(#_PWD8xlg5PF32eiY&&FG$Z=I?sOSz%PsVNFXgpC96(LyR3yY|9B<<%w zYDF;~YJzn1)0)WJxUWTABvBJ&^sKmsS#`2b7>6(}5-150CI3o9mZ!v^k`zsS4Cx*M zc3vr)Nd-GwKxgf<^W7*5Qpv=Y%lHn)p#AKJC0ogi4qq^6i}MjyMo&;#mS}(fNo7-7 z1gWIO^L-uW8jqme?8XE{Iitm#HbK~>+cp@>-qAK+oWf;a z&Dc83>0L2AIv!t}!e{47_^20|NFZPpM2^PxZt!3Ks47urHE3T` z=kqHiv>u8Qw4{+R!(4M4_~M#2F#toG9QfmnQj``ig#`a>{OOifF#vX`o2Hp#yO{wi7iR* z4;eY5?b%eVBx0h#uh~u|`By#Pu+x81%Oi9Z5+O)P-QGdfIiS4Kr;9`h5<+ijOE~l% u!-SLOH+>QWK@bE%5ClOG1VIo)qwqf-Rt3m* { public: - ImageRGBMatcher(const wxImage& image) + ImageRGBMatcher(const wxImage& image, int tolerance) : m_image(image) + , m_tolerance(tolerance) { } @@ -53,7 +54,8 @@ public: { for ( int y = 0; y < m_image.GetHeight(); ++y ) { - if ( *d1 != *d2 ) + const unsigned char diff = *d1 > * d2 ? *d1 - *d2 : *d2 - *d1; + if (diff > m_tolerance) { m_diffDesc.Printf ( @@ -72,11 +74,11 @@ public: } } - // We should never get here as we know that the images are different - // and so should have returned from inside the loop above. - wxFAIL_MSG("unreachable"); + // We can only get here when the images are different AND we've not exited the + // method from the loop. That implies the tolerance must have caused this. + wxASSERT_MSG(m_tolerance > 0, "Unreachable without tolerance"); - return false; + return true; } std::string describe() const wxOVERRIDE @@ -92,12 +94,67 @@ public: private: const wxImage m_image; + const int m_tolerance; mutable wxString m_diffDesc; }; inline ImageRGBMatcher RGBSameAs(const wxImage& image) { - return ImageRGBMatcher(image); + return ImageRGBMatcher(image, 0); +} + +// Allows small differences (within given tolerance) for r, g, and b values. +inline ImageRGBMatcher RGBSimilarTo(const wxImage& image, int tolerance) +{ + return ImageRGBMatcher(image, tolerance); +} + +class ImageAlphaMatcher : public Catch::MatcherBase +{ +public: + ImageAlphaMatcher(unsigned char alpha) + : m_alpha(alpha) + { + } + + bool match(const wxImage& other) const wxOVERRIDE + { + if (!other.HasAlpha()) + { + m_diffDesc = "no alpha data"; + return false; + } + + unsigned char center_alpha = + *(other.GetAlpha() + (other.GetWidth() / 2) + (other.GetHeight() / 2 * other.GetWidth())); + + if (m_alpha != center_alpha) + { + m_diffDesc.Printf("got alpha %u", center_alpha); + return false; + } + + return true; + } + + std::string describe() const wxOVERRIDE + { + std::string desc; + + if (!m_diffDesc.empty()) + desc = m_diffDesc.ToStdString(wxConvUTF8); + + return desc; + } + +private: + const unsigned char m_alpha; + mutable wxString m_diffDesc; +}; + +inline ImageAlphaMatcher CenterAlphaPixelEquals(unsigned char alpha) +{ + return ImageAlphaMatcher(alpha); } #endif // _WX_TESTS_TESTIMAGE_H_ From 451ed78dcdacfd94d04bda6dddd73dbb4bbc92e4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 25 Sep 2020 01:09:47 +0200 Subject: [PATCH 037/105] Mark wxImageAlphaBlendMode as being new since 3.1.5 It doesn't matter much, but it, and the corresponding parameter, will be available in this version and not (only) in 3.2.0. --- interface/wx/image.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/wx/image.h b/interface/wx/image.h index a2c5b25f98..1c7288bd82 100644 --- a/interface/wx/image.h +++ b/interface/wx/image.h @@ -64,7 +64,7 @@ enum wxImageResizeQuality /** Constants for wxImage::Paste() for specifying alpha blending option. - @since 3.2.0 + @since 3.1.5 */ enum wxImageAlphaBlendMode { @@ -822,7 +822,7 @@ public: Takes care of the mask colour and out of bounds problems. @param alphaBlend - This parameter (new in wx 3.2.0) determines whether the alpha values + This parameter (new in wx 3.1.5) determines whether the alpha values of the original image replace (default) or are composed with the alpha channel of this image. Notice that alpha blending overrides the mask handling. From 08599d894fd91ff32b3d0a9b0f2e8d4dd4d6a57f Mon Sep 17 00:00:00 2001 From: PB Date: Fri, 25 Sep 2020 21:29:20 +0200 Subject: [PATCH 038/105] Fix displaying Flush() in wxClipboard docs note Just remove the '@' which was probably there by accident but made the function name disappear. --- interface/wx/clipbrd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/wx/clipbrd.h b/interface/wx/clipbrd.h index c8fb6fc277..ab9ed206cb 100644 --- a/interface/wx/clipbrd.h +++ b/interface/wx/clipbrd.h @@ -57,7 +57,7 @@ the end-user's machine. In order for the clipboard data to persist after the window closes, a clipboard manager must be installed. Some clipboard managers will automatically flush the clipboard after each new piece of - data is added, while others will not. The @Flush() function will force + data is added, while others will not. The Flush() function will force the clipboard manager to flush the data. @library{wxcore} From 6fac6c0b356e174db41af4bf00f6016fcbc07003 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sat, 26 Sep 2020 01:43:20 +0200 Subject: [PATCH 039/105] Add unit tests of coordinates conversion functions --- interface/wx/dc.h | 36 +- tests/Makefile.in | 4 + tests/graphics/coords.cpp | 852 +++++++++++++++++++++++++++++++++ tests/makefile.bcc | 4 + tests/makefile.gcc | 4 + tests/makefile.vc | 4 + tests/test.bkl | 1 + tests/test_gui.vcxproj | 1 + tests/test_gui.vcxproj.filters | 3 + tests/test_vc7_test_gui.vcproj | 3 + tests/test_vc8_test_gui.vcproj | 4 + tests/test_vc9_test_gui.vcproj | 4 + 12 files changed, 916 insertions(+), 4 deletions(-) create mode 100644 tests/graphics/coords.cpp diff --git a/interface/wx/dc.h b/interface/wx/dc.h index bf1ca7db64..10a0392df5 100644 --- a/interface/wx/dc.h +++ b/interface/wx/dc.h @@ -206,52 +206,80 @@ public: /** Convert @e device X coordinate to logical coordinate, using the current mapping mode, user scale factor, device origin and axis orientation. + + @note Affine transformation applied to the coordinate system + with SetTransformMatrix() is not taken into account. */ wxCoord DeviceToLogicalX(wxCoord x) const; /** Convert @e device X coordinate to relative logical coordinate, using the current mapping mode and user scale factor but ignoring the - axis orientation. Use this for converting a width, for example. + axis orientation. Use this for converting a horizontal distance like + for example a width. + + @note Affine transformation applied to the coordinate system + with SetTransformMatrix() is not taken into account. */ wxCoord DeviceToLogicalXRel(wxCoord x) const; /** Converts @e device Y coordinate to logical coordinate, using the current mapping mode, user scale factor, device origin and axis orientation. + + @note Affine transformation applied to the coordinate system + with SetTransformMatrix() is not taken into account. */ wxCoord DeviceToLogicalY(wxCoord y) const; /** Convert @e device Y coordinate to relative logical coordinate, using the current mapping mode and user scale factor but ignoring the - axis orientation. Use this for converting a height, for example. + axis orientation. Use this for converting a vertical distance like + for example a height. + + @note Affine transformation applied to the coordinate system + with SetTransformMatrix() is not taken into account. */ wxCoord DeviceToLogicalYRel(wxCoord y) const; /** Converts logical X coordinate to device coordinate, using the current mapping mode, user scale factor, device origin and axis orientation. + + @note Affine transformation applied to the coordinate system + with SetTransformMatrix() is not taken into account. */ wxCoord LogicalToDeviceX(wxCoord x) const; /** Converts logical X coordinate to relative device coordinate, using the current mapping mode and user scale factor but ignoring the - axis orientation. Use this for converting a width, for example. + axis orientation. Use this for converting a horizontal distance like + for example a width. + + @note Affine transformation applied to the coordinate system + with SetTransformMatrix() is not taken into account. */ wxCoord LogicalToDeviceXRel(wxCoord x) const; /** Converts logical Y coordinate to device coordinate, using the current mapping mode, user scale factor, device origin and axis orientation. + + @note Affine transformation applied to the coordinate system + with SetTransformMatrix() is not taken into account. */ wxCoord LogicalToDeviceY(wxCoord y) const; /** Converts logical Y coordinate to relative device coordinate, using the current mapping mode and user scale factor but ignoring the - axis orientation. Use this for converting a height, for example. + axis orientation. Use this for converting a vertical distance like + for example a height. + + @note Affine transformation applied to the coordinate system + with SetTransformMatrix() is not taken into account. */ wxCoord LogicalToDeviceYRel(wxCoord y) const; diff --git a/tests/Makefile.in b/tests/Makefile.in index 5cd6cc7bda..eb43137e9d 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -185,6 +185,7 @@ TEST_GUI_OBJECTS = \ test_gui_affinematrix.o \ test_gui_boundingbox.o \ test_gui_clippingbox.o \ + test_gui_coords.o \ test_gui_graphmatrix.o \ test_gui_graphpath.o \ test_gui_config.o \ @@ -899,6 +900,9 @@ test_gui_boundingbox.o: $(srcdir)/graphics/boundingbox.cpp $(TEST_GUI_ODEP) test_gui_clippingbox.o: $(srcdir)/graphics/clippingbox.cpp $(TEST_GUI_ODEP) $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/graphics/clippingbox.cpp +test_gui_coords.o: $(srcdir)/graphics/coords.cpp $(TEST_GUI_ODEP) + $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/graphics/coords.cpp + test_gui_graphmatrix.o: $(srcdir)/graphics/graphmatrix.cpp $(TEST_GUI_ODEP) $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/graphics/graphmatrix.cpp diff --git a/tests/graphics/coords.cpp b/tests/graphics/coords.cpp new file mode 100644 index 0000000000..67e376ebcd --- /dev/null +++ b/tests/graphics/coords.cpp @@ -0,0 +1,852 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: tests/graphics/coords.cpp +// Purpose: Coordinates conversion unit tests +// Author: Artur Wieczorek +// Created: 2020-09-25 +// Copyright: (c) 2020 wxWidgets development team +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "testprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/bitmap.h" +#include "wx/dcgraph.h" +#include "wx/dcmemory.h" + + +// ---------------------------------------------------------------------------- +// test class +// ---------------------------------------------------------------------------- + +static const wxSize s_dcSize(100, 100); +static const wxPoint s_posDev(24, 57); +static const wxSize s_dimDev(40, 15); + +// ==================== +// wxDC / wxGCDC tests +// ==================== + +class CoordinatesDCTestCaseBase +{ +public: + CoordinatesDCTestCaseBase() + { + m_bmp.Create(s_dcSize); + m_dc = NULL; + } + + virtual ~CoordinatesDCTestCaseBase() + { + m_bmp = wxNullBitmap; + } + +protected: + wxBitmap m_bmp; + wxDC* m_dc; +}; + +// =========== +// wxDC tests +// =========== + +class CoordinatesDCTestCase : public CoordinatesDCTestCaseBase +{ +public: + CoordinatesDCTestCase() + { + m_mdc.SelectObject(m_bmp); + m_dc = &m_mdc; + } + + virtual ~CoordinatesDCTestCase() + { + m_mdc.SelectObject(wxNullBitmap); + } + +protected: + wxMemoryDC m_mdc; +}; + +#if wxUSE_GRAPHICS_CONTEXT +// ============= +// wxGCDC tests +// ============= + +class CoordinatesGCDCTestCase : public CoordinatesDCTestCase +{ +public: + CoordinatesGCDCTestCase() + { + m_gcdc = new wxGCDC(m_mdc); + + wxGraphicsContext* ctx = m_gcdc->GetGraphicsContext(); + ctx->SetAntialiasMode(wxANTIALIAS_NONE); + ctx->DisableOffset(); + + m_dc = m_gcdc; + } + + virtual ~CoordinatesGCDCTestCase() + { + delete m_gcdc; + } + +protected: + wxGCDC* m_gcdc; +}; +#endif // wxUSE_GRAPHICS_CONTEXT + +// ===== Implementation ===== + +static void InitialState(wxDC* dc) +{ + // Check initial state + + wxPoint origin = dc->GetDeviceOrigin(); + CHECK(origin.x == 0); + CHECK(origin.y == 0); + + origin = dc->GetLogicalOrigin(); + CHECK(origin.x == 0); + CHECK(origin.y == 0); + + double sx, sy; + dc->GetUserScale(&sx, &sy); + CHECK(sx == 1.0); + CHECK(sy == 1.0); + + dc->GetLogicalScale(&sx, &sy); + CHECK(sx == 1.0); + CHECK(sy == 1.0); + +#if wxUSE_DC_TRANSFORM_MATRIX + if ( dc->CanUseTransformMatrix() ) + { + wxAffineMatrix2D m = dc->GetTransformMatrix(); + CHECK(m.IsIdentity() == true); + } +#endif // wxUSE_DC_TRANSFORM_MATRIX +} + +static void NoTransform(wxDC *dc) +{ + // No transformations + + // First convert from device to logical coordinates + wxPoint posLog; + posLog.x = dc->DeviceToLogicalX(s_posDev.x); + posLog.y = dc->DeviceToLogicalY(s_posDev.y); + CHECK(posLog.x == s_posDev.x); + CHECK(posLog.y == s_posDev.y); + + wxSize dimLog; + dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x); + dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y); + CHECK(dimLog.x == s_dimDev.x); + CHECK(dimLog.y == s_dimDev.y); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev.x = dc->LogicalToDeviceX(posLog.x); + posDev.y = dc->LogicalToDeviceY(posLog.y); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev.x = dc->LogicalToDeviceXRel(dimLog.x); + dimDev.y = dc->LogicalToDeviceYRel(dimLog.y); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + +static void DeviceOriginChanged(wxDC* dc) +{ + // Only device origin is changed + const wxCoord dx = 10; + const wxCoord dy = 15; + dc->SetDeviceOrigin(dx, dy); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog.x = dc->DeviceToLogicalX(s_posDev.x); + posLog.y = dc->DeviceToLogicalY(s_posDev.y); + CHECK(posLog.x == s_posDev.x - dx); + CHECK(posLog.y == s_posDev.y - dy); + + wxSize dimLog; + dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x); + dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y); + CHECK(dimLog.x == s_dimDev.x); + CHECK(dimLog.y == s_dimDev.y); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev.x = dc->LogicalToDeviceX(posLog.x); + posDev.y = dc->LogicalToDeviceY(posLog.y); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev.x = dc->LogicalToDeviceXRel(dimLog.x); + dimDev.y = dc->LogicalToDeviceYRel(dimLog.y); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + +static void LogicalOriginChanged(wxDC* dc) +{ + // Only logical origin is changed + const wxCoord dx = -15; + const wxCoord dy = -20; + dc->SetLogicalOrigin(dx, dy); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog.x = dc->DeviceToLogicalX(s_posDev.x); + posLog.y = dc->DeviceToLogicalY(s_posDev.y); + CHECK(posLog.x == s_posDev.x + dx); + CHECK(posLog.y == s_posDev.y + dy); + + wxSize dimLog; + dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x); + dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y); + CHECK(dimLog.x == s_dimDev.x); + CHECK(dimLog.y == s_dimDev.y); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev.x = dc->LogicalToDeviceX(posLog.x); + posDev.y = dc->LogicalToDeviceY(posLog.y); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev.x = dc->LogicalToDeviceXRel(dimLog.x); + dimDev.y = dc->LogicalToDeviceYRel(dimLog.y); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + +static void UserScaleChanged(wxDC* dc) +{ + // Only user scale is changed + const double sx = 2.0; + const double sy = 3.0; + dc->SetUserScale(sx, sy); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog.x = dc->DeviceToLogicalX(s_posDev.x); + posLog.y = dc->DeviceToLogicalY(s_posDev.y); + CHECK(posLog.x == wxRound(s_posDev.x / sx)); + CHECK(posLog.y == wxRound(s_posDev.y / sy)); + + wxSize dimLog; + dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x); + dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y); + CHECK(dimLog.x == wxRound(s_dimDev.x / sx)); + CHECK(dimLog.y == wxRound(s_dimDev.y / sy)); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev.x = dc->LogicalToDeviceX(posLog.x); + posDev.y = dc->LogicalToDeviceY(posLog.y); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev.x = dc->LogicalToDeviceXRel(dimLog.x); + dimDev.y = dc->LogicalToDeviceYRel(dimLog.y); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + +static void LogicalScaleChanged(wxDC* dc) +{ + // Only logical scale is changed + const double sx = 2.0; + const double sy = 3.0; + dc->SetLogicalScale(sx, sy); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog.x = dc->DeviceToLogicalX(s_posDev.x); + posLog.y = dc->DeviceToLogicalY(s_posDev.y); + CHECK(posLog.x == wxRound(s_posDev.x / sx)); + CHECK(posLog.y == wxRound(s_posDev.y / sy)); + + wxSize dimLog; + dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x); + dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y); + CHECK(dimLog.x == wxRound(s_dimDev.x / sx)); + CHECK(dimLog.y == wxRound(s_dimDev.y / sy)); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev.x = dc->LogicalToDeviceX(posLog.x); + posDev.y = dc->LogicalToDeviceY(posLog.y); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev.x = dc->LogicalToDeviceXRel(dimLog.x); + dimDev.y = dc->LogicalToDeviceYRel(dimLog.y); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + +static void TransformedStd(wxDC* dc) +{ + // Apply all standardd transformations + dc->SetDeviceOrigin(10, 15); + dc->SetUserScale(0.5, 2.0); + dc->SetLogicalScale(4.0, 1.5); + dc->SetLogicalOrigin(-15, -20); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog.x = dc->DeviceToLogicalX(s_posDev.x); + posLog.y = dc->DeviceToLogicalY(s_posDev.y); + CHECK(posLog.x == -8); + CHECK(posLog.y == -6); + + wxSize dimLog; + dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x); + dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y); + CHECK(dimLog.x == 20); + CHECK(dimLog.y == 5); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev.x = dc->LogicalToDeviceX(posLog.x); + posDev.y = dc->LogicalToDeviceY(posLog.y); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev.x = dc->LogicalToDeviceXRel(dimLog.x); + dimDev.y = dc->LogicalToDeviceYRel(dimLog.y); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + +static void TransformedWithMatrix(wxDC* dc) +{ + // Apply transformation matrix only +#if wxUSE_DC_TRANSFORM_MATRIX + if ( dc->CanUseTransformMatrix() ) + { + // Apply translation and scaling only + wxAffineMatrix2D m = dc->GetTransformMatrix(); + m.Translate(10, 15); + m.Scale(2.0, 3.0); + dc->SetTransformMatrix(m); + + // First convert from device to logical coordinates + // Results should be nagative because legacy functions + // don't take affine transformation into account. + m.Invert(); + wxPoint2DDouble posLogRef = m.TransformPoint(wxPoint2DDouble(s_posDev)); + wxPoint posLog; + posLog.x = dc->DeviceToLogicalX(s_posDev.x); + posLog.y = dc->DeviceToLogicalY(s_posDev.y); + CHECK_FALSE(posLog.x == wxRound(posLogRef.m_x)); + CHECK_FALSE(posLog.y == wxRound(posLogRef.m_y)); + CHECK(posLog.x == s_posDev.x); + CHECK(posLog.y == s_posDev.y); + + wxPoint2DDouble dimLogRef = m.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y)); + wxSize dimLog; + dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x); + dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y); + CHECK_FALSE(dimLog.x == wxRound(dimLogRef.m_x)); + CHECK_FALSE(dimLog.y == wxRound(dimLogRef.m_y)); + CHECK(dimLog.x == s_dimDev.x); + CHECK(dimLog.y == s_dimDev.y); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev.x = dc->LogicalToDeviceX(posLog.x); + posDev.y = dc->LogicalToDeviceY(posLog.y); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev.x = dc->LogicalToDeviceXRel(dimLog.x); + dimDev.y = dc->LogicalToDeviceYRel(dimLog.y); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); + } +#endif // wxUSE_DC_TRANSFORM_MATRIX +} + +static void TransformedWithMatrixAndStd(wxDC* dc) +{ + // Apply combination of standard and matrix transformations +#if wxUSE_DC_TRANSFORM_MATRIX + if ( dc->CanUseTransformMatrix() ) + { + dc->SetDeviceOrigin(10, 15); + + dc->SetUserScale(0.5, 1.5); + dc->SetLogicalScale(4.0, 2.0); + dc->SetLogicalOrigin(-15, -20); + + wxAffineMatrix2D m = dc->GetTransformMatrix(); + m.Translate(10, 18); + m.Scale(2.0, 0.5); + dc->SetTransformMatrix(m); + + // First convert from device to logical coordinates + // Results should be nagative because legacy functions + // don't take affine transformation into account. + wxAffineMatrix2D m1; + m1.Translate(10 - (-15) * (0.5 * 4.0), 15 - (-20) * (1.5 * 2.0)); + m1.Scale(0.5 * 4.0, 1.5 * 2.0); + m1.Concat(m); + m1.Invert(); + + wxPoint2DDouble posLogRef = m1.TransformPoint(wxPoint2DDouble(s_posDev)); + wxPoint posLog; + posLog.x = dc->DeviceToLogicalX(s_posDev.x); + posLog.y = dc->DeviceToLogicalY(s_posDev.y); + CHECK_FALSE(posLog.x == wxRound(posLogRef.m_x)); + CHECK_FALSE(posLog.y == wxRound(posLogRef.m_y)); + + wxPoint2DDouble dimLogRef = m1.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y)); + wxSize dimLog; + dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x); + dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y); + CHECK_FALSE(dimLog.x == wxRound(dimLogRef.m_x)); + CHECK_FALSE(dimLog.y == wxRound(dimLogRef.m_y)); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev.x = dc->LogicalToDeviceX(posLog.x); + posDev.y = dc->LogicalToDeviceY(posLog.y); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev.x = dc->LogicalToDeviceXRel(dimLog.x); + dimDev.y = dc->LogicalToDeviceYRel(dimLog.y); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); + } +#endif // wxUSE_DC_TRANSFORM_MATRIX +} + +static void RotatedWithMatrix(wxDC* dc) +{ + // Apply matrix transformations with rotation component +#if wxUSE_DC_TRANSFORM_MATRIX + if ( dc->CanUseTransformMatrix() ) + { + wxAffineMatrix2D m = dc->GetTransformMatrix(); + m.Rotate(6 * M_PI / 180.0); + m.Translate(10, 15); + m.Scale(2.0, 3.0); + dc->SetTransformMatrix(m); + + // First convert from device to logical coordinates + // Results should be nagative because legacy functions + // don't take affine transformation into account. + m.Invert(); + wxPoint2DDouble posLogRef = m.TransformPoint(wxPoint2DDouble(s_posDev)); + wxPoint posLog; + posLog.x = dc->DeviceToLogicalX(s_posDev.x); + posLog.y = dc->DeviceToLogicalY(s_posDev.y); + CHECK_FALSE(posLog.x == wxRound(posLogRef.m_x)); + CHECK_FALSE(posLog.y == wxRound(posLogRef.m_y)); + CHECK(posLog.x == s_posDev.x); + CHECK(posLog.y == s_posDev.y); + + wxPoint2DDouble dimLogRef = m.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y)); + wxSize dimLog; + dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x); + dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y); + CHECK_FALSE(dimLog.x == wxRound(dimLogRef.m_x)); + CHECK_FALSE(dimLog.y == wxRound(dimLogRef.m_y)); + CHECK(dimLog.x == s_dimDev.x); + CHECK(dimLog.y == s_dimDev.y); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev.x = dc->LogicalToDeviceX(posLog.x); + posDev.y = dc->LogicalToDeviceY(posLog.y); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev.x = dc->LogicalToDeviceXRel(dimLog.x); + dimDev.y = dc->LogicalToDeviceYRel(dimLog.y); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); + } +#endif // wxUSE_DC_TRANSFORM_MATRIX +} + +// For GTK+ 3 and OSX wxDC is equivalent to wxGCDC +// so it doesn't need to be tested individually. +#if !defined(__WXGTK3__) && !defined(__WXOSX__) +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::InitialState", "[coordinates]") +{ + // Check initial state + InitialState(m_dc); +} + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::NoTransform", "[coordinates]") +{ + // No transformations + NoTransform(m_dc); +} + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::DeviceOriginChanged", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalOriginChanged", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::UserScaleChanged", "[coordinates]") +{ + // Only user scale is changed + UserScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalScaleChanged", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedStd", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrix", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrix(m_dc); +} + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrixAndStd", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::RotatedWithMatrix", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrix(m_dc); +} +#endif // !__WXGTK3__ && !_WXOSX__ + +#if wxUSE_GRAPHICS_CONTEXT +// For MSW we have individual test cases for each graphics renderer +// so we don't need to test wxGCDC with default renderer. +#ifndef __WXMSW__ +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::InitialState", "[coordinates]") +{ + // Check initial state + InitialState(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::NoTransform", "[coordinates]") +{ + // No transformations + NoTransform(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::DeviceOriginChanged", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalOriginChanged", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::UserScaleChanged", "[coordinates]") +{ + // Only user scale is changed + UserScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalScaleChanged", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedStd", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrix", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrix(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrixAndStd", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::RotatedWithMatrix", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrix(m_dc); +} +#else// GDI+ and Direct2D are available only under MSW. +#if wxUSE_GRAPHICS_GDIPLUS +class CoordinatesGCDCGDIPlusTestCase : public CoordinatesGCDCTestCase +{ +public: + CoordinatesGCDCGDIPlusTestCase() + { + wxGraphicsRenderer* rend = wxGraphicsRenderer::GetGDIPlusRenderer(); + wxGraphicsContext* ctx = rend->CreateContext(m_mdc); + REQUIRE(ctx != NULL); + m_gcdc->SetGraphicsContext(ctx); + } + + virtual ~CoordinatesGCDCGDIPlusTestCase() {} +}; + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::InitialState", "[coordinates]") +{ + // Check initial state + InitialState(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::NoTransform", "[coordinates]") +{ + // No transformations + NoTransform(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::DeviceOriginChanged", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalOriginChanged", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::UserScaleChanged", "[coordinates]") +{ + // Only user scale is changed + UserScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalScaleChanged", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedStd", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrix", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrix(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrixAndStd", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::RotatedWithMatrix", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrix(m_dc); +} +#endif // wxUSE_GRAPHICS_GDIPLUS + +#if wxUSE_GRAPHICS_DIRECT2D +class CoordinatesGCDCDirect2DTestCase : public CoordinatesGCDCTestCase +{ +public: + CoordinatesGCDCDirect2DTestCase() + { + wxGraphicsRenderer* rend = wxGraphicsRenderer::GetDirect2DRenderer(); + wxGraphicsContext* ctx = rend->CreateContext(m_mdc); + REQUIRE(ctx != NULL); + m_gcdc->SetGraphicsContext(ctx); + } + + virtual ~CoordinatesGCDCDirect2DTestCase() {} +}; + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::InitialState", "[coordinates]") +{ + // Check initial state + InitialState(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::NoTransform", "[coordinates]") +{ + // No transformations + NoTransform(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::DeviceOriginChanged", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalOriginChanged", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::UserScaleChanged", "[coordinates]") +{ + // Only user scale is changed + UserScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalScaleChanged", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedStd", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrix", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrix(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrixAndStd", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::RotatedWithMatrix", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrix(m_dc); +} +#endif // wxUSE_GRAPHICS_DIRECT2D +#endif // __WXMSW__/!__WXMSW__ + +#if wxUSE_CAIRO +class CoordinatesGCDCCairoTestCase : public CoordinatesGCDCTestCase +{ +public: + CoordinatesGCDCCairoTestCase() + { + wxGraphicsRenderer* rend = wxGraphicsRenderer::GetCairoRenderer(); + wxGraphicsContext* ctx = rend->CreateContext(m_mdc); + REQUIRE(ctx != NULL); + m_gcdc->SetGraphicsContext(ctx); + } + + virtual ~CoordinatesGCDCCairoTestCase() {} +}; + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::InitialState", "[coordinates]") +{ + // Check initial state + InitialState(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::NoTransform", "[coordinates]") +{ + // No transformations + NoTransform(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::DeviceOriginChanged", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalOriginChanged", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::UserScaleChanged", "[coordinates]") +{ + // Only user scale is changed + UserScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalScaleChanged", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChanged(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedStd", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrix", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrix(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrixAndStd", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStd(m_dc); +} + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::RotatedWithMatrix", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrix(m_dc); +} +#endif // wxUSE_CAIRO +#endif // wxUSE_GRAPHICS_CONTEXT diff --git a/tests/makefile.bcc b/tests/makefile.bcc index 6be3ae8a33..2a503e7998 100644 --- a/tests/makefile.bcc +++ b/tests/makefile.bcc @@ -168,6 +168,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_affinematrix.obj \ $(OBJS)\test_gui_boundingbox.obj \ $(OBJS)\test_gui_clippingbox.obj \ + $(OBJS)\test_gui_coords.obj \ $(OBJS)\test_gui_graphmatrix.obj \ $(OBJS)\test_gui_graphpath.obj \ $(OBJS)\test_gui_config.obj \ @@ -907,6 +908,9 @@ $(OBJS)\test_gui_boundingbox.obj: .\graphics\boundingbox.cpp $(OBJS)\test_gui_clippingbox.obj: .\graphics\clippingbox.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\graphics\clippingbox.cpp +$(OBJS)\test_gui_coords.obj: .\graphics\coords.cpp + $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\graphics\coords.cpp + $(OBJS)\test_gui_graphmatrix.obj: .\graphics\graphmatrix.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\graphics\graphmatrix.cpp diff --git a/tests/makefile.gcc b/tests/makefile.gcc index 88cb64af69..adfa87505e 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -163,6 +163,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_affinematrix.o \ $(OBJS)\test_gui_boundingbox.o \ $(OBJS)\test_gui_clippingbox.o \ + $(OBJS)\test_gui_coords.o \ $(OBJS)\test_gui_graphmatrix.o \ $(OBJS)\test_gui_graphpath.o \ $(OBJS)\test_gui_config.o \ @@ -892,6 +893,9 @@ $(OBJS)\test_gui_boundingbox.o: ./graphics/boundingbox.cpp $(OBJS)\test_gui_clippingbox.o: ./graphics/clippingbox.cpp $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\test_gui_coords.o: ./graphics/coords.cpp + $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\test_gui_graphmatrix.o: ./graphics/graphmatrix.cpp $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< diff --git a/tests/makefile.vc b/tests/makefile.vc index 990d47e105..4ba6a5643d 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -177,6 +177,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_affinematrix.obj \ $(OBJS)\test_gui_boundingbox.obj \ $(OBJS)\test_gui_clippingbox.obj \ + $(OBJS)\test_gui_coords.obj \ $(OBJS)\test_gui_graphmatrix.obj \ $(OBJS)\test_gui_graphpath.obj \ $(OBJS)\test_gui_config.obj \ @@ -1320,6 +1321,9 @@ $(OBJS)\test_gui_boundingbox.obj: .\graphics\boundingbox.cpp $(OBJS)\test_gui_clippingbox.obj: .\graphics\clippingbox.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\graphics\clippingbox.cpp +$(OBJS)\test_gui_coords.obj: .\graphics\coords.cpp + $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\graphics\coords.cpp + $(OBJS)\test_gui_graphmatrix.obj: .\graphics\graphmatrix.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\graphics\graphmatrix.cpp diff --git a/tests/test.bkl b/tests/test.bkl index 2588593b05..74d0cc1c50 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -181,6 +181,7 @@ graphics/affinematrix.cpp graphics/boundingbox.cpp graphics/clippingbox.cpp + graphics/coords.cpp graphics/graphmatrix.cpp graphics/graphpath.cpp config/config.cpp diff --git a/tests/test_gui.vcxproj b/tests/test_gui.vcxproj index 754fdb8d44..7032b4ce33 100644 --- a/tests/test_gui.vcxproj +++ b/tests/test_gui.vcxproj @@ -547,6 +547,7 @@ + diff --git a/tests/test_gui.vcxproj.filters b/tests/test_gui.vcxproj.filters index e61c1bf4fd..0eede89fd6 100644 --- a/tests/test_gui.vcxproj.filters +++ b/tests/test_gui.vcxproj.filters @@ -293,6 +293,9 @@ Source Files + + Source Files + Source Files diff --git a/tests/test_vc7_test_gui.vcproj b/tests/test_vc7_test_gui.vcproj index f18a1a38ce..ec237145b5 100644 --- a/tests/test_vc7_test_gui.vcproj +++ b/tests/test_vc7_test_gui.vcproj @@ -358,6 +358,9 @@ + + diff --git a/tests/test_vc8_test_gui.vcproj b/tests/test_vc8_test_gui.vcproj index ccc8576f4a..dd1700c187 100644 --- a/tests/test_vc8_test_gui.vcproj +++ b/tests/test_vc8_test_gui.vcproj @@ -914,6 +914,10 @@ RelativePath=".\config\config.cpp" > + + diff --git a/tests/test_vc9_test_gui.vcproj b/tests/test_vc9_test_gui.vcproj index c9c6d5a4e8..ff01099d23 100644 --- a/tests/test_vc9_test_gui.vcproj +++ b/tests/test_vc9_test_gui.vcproj @@ -886,6 +886,10 @@ RelativePath=".\config\config.cpp" > + + From 2c3c841719b1a96bcff8fb0b13dae134b8dd72b7 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 27 Sep 2020 10:38:08 +0200 Subject: [PATCH 040/105] Implement platform-specific coordinate conversion functions Generic wxDC::DeviceToLogicalRel{X|Y}() and wxDC::LogicalToDeviceRel{X|Y}() functions don't take into account scaling applied with wxDC::SetTransformMatrix(). We need to implement in wxDCImpl and its platform-specific derivates new conversion functions that take all applied transformations into account. See #18923. --- include/wx/dc.h | 2 ++ include/wx/dcgraph.h | 2 ++ include/wx/msw/dc.h | 2 ++ src/common/dcbase.cpp | 10 ++++++++++ src/common/dcgraph.cpp | 16 ++++++++++++++++ src/msw/dc.cpp | 22 ++++++++++++++++++++++ 6 files changed, 54 insertions(+) diff --git a/include/wx/dc.h b/include/wx/dc.h index 7cf8ba7873..41f6d8212e 100644 --- a/include/wx/dc.h +++ b/include/wx/dc.h @@ -325,6 +325,8 @@ public: // coordinates conversions and transforms virtual wxPoint DeviceToLogical(wxCoord x, wxCoord y) const; virtual wxPoint LogicalToDevice(wxCoord x, wxCoord y) const; + virtual wxSize DeviceToLogicalRel(int x, int y) const; + virtual wxSize LogicalToDeviceRel(int x, int y) const; // bounding box diff --git a/include/wx/dcgraph.h b/include/wx/dcgraph.h index 4622a3534a..e483d58e81 100644 --- a/include/wx/dcgraph.h +++ b/include/wx/dcgraph.h @@ -124,6 +124,8 @@ public: // coordinates conversions and transforms virtual wxPoint DeviceToLogical(wxCoord x, wxCoord y) const wxOVERRIDE; virtual wxPoint LogicalToDevice(wxCoord x, wxCoord y) const wxOVERRIDE; + virtual wxSize DeviceToLogicalRel(int x, int y) const wxOVERRIDE; + virtual wxSize LogicalToDeviceRel(int x, int y) const wxOVERRIDE; // the true implementations virtual bool DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, diff --git a/include/wx/msw/dc.h b/include/wx/msw/dc.h index faaab34283..677eeac823 100644 --- a/include/wx/msw/dc.h +++ b/include/wx/msw/dc.h @@ -88,6 +88,8 @@ public: virtual wxPoint DeviceToLogical(wxCoord x, wxCoord y) const wxOVERRIDE; virtual wxPoint LogicalToDevice(wxCoord x, wxCoord y) const wxOVERRIDE; + virtual wxSize DeviceToLogicalRel(int x, int y) const wxOVERRIDE; + virtual wxSize LogicalToDeviceRel(int x, int y) const wxOVERRIDE; #if wxUSE_DC_TRANSFORM_MATRIX virtual bool CanUseTransformMatrix() const wxOVERRIDE; diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index 59f61bce0a..6f351dfdc1 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -512,6 +512,16 @@ wxPoint wxDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const return wxPoint(LogicalToDeviceX(x), LogicalToDeviceY(y)); } +wxSize wxDCImpl::DeviceToLogicalRel(int x, int y) const +{ + return wxSize(DeviceToLogicalXRel(x), DeviceToLogicalYRel(y)); +} + +wxSize wxDCImpl::LogicalToDeviceRel(int x, int y) const +{ + return wxSize(LogicalToDeviceXRel(x), LogicalToDeviceYRel(y)); +} + void wxDCImpl::ComputeScaleAndOrigin() { m_scaleX = m_logicalScaleX * m_userScaleX; diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp index cd6c8d206e..ff53f27331 100644 --- a/src/common/dcgraph.cpp +++ b/src/common/dcgraph.cpp @@ -613,6 +613,22 @@ wxPoint wxGCDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const return wxPoint(wxRound(px), wxRound(py)); } +wxSize wxGCDCImpl::DeviceToLogicalRel(int x, int y) const +{ + wxDouble dx = x; + wxDouble dy = y; + m_matrixCurrentInv.TransformDistance(&dx, &dy); + return wxSize(wxRound(dx), wxRound(dy)); +} + +wxSize wxGCDCImpl::LogicalToDeviceRel(int x, int y) const +{ + wxDouble dx = x; + wxDouble dy = y; + m_matrixCurrent.TransformDistance(&dx, &dy); + return wxSize(wxRound(dx), wxRound(dy)); +} + bool wxGCDCImpl::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxColour& WXUNUSED(col), wxFloodFillStyle WXUNUSED(style)) diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index 6ebc77b68e..fe7fcd7737 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -2118,6 +2118,28 @@ wxPoint wxMSWDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const return wxPoint(p[0].x, p[0].y); } +wxSize wxMSWDCImpl::DeviceToLogicalRel(int x, int y) const +{ + POINT p[2]; + p[0].x = 0; + p[0].y = 0; + p[1].x = x; + p[1].y = y; + ::DPtoLP(GetHdc(), p, WXSIZEOF(p)); + return wxSize(p[1].x-p[0].x, p[1].y-p[0].y); +} + +wxSize wxMSWDCImpl::LogicalToDeviceRel(int x, int y) const +{ + POINT p[2]; + p[0].x = 0; + p[0].y = 0; + p[1].x = x; + p[1].y = y; + ::LPtoDP(GetHdc(), p, WXSIZEOF(p)); + return wxSize(p[1].x-p[0].x, p[1].y-p[0].y); +} + // ---------------------------------------------------------------------------- // Transform matrix // ---------------------------------------------------------------------------- From 7153eaf6ec028051e268d6b1178528c88d246bd6 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 27 Sep 2020 11:16:26 +0200 Subject: [PATCH 041/105] Implement new coordinates conversion functions in wxDC Current DeviceToLogical{X|Y}(), LogicalToDevice{X|Y}(), DeviceToLogicalRel{X|Y}(), LogicalToDeviceRel{X|Y}() functions don't take into account transformations applied with SetTransformMatrix() so conversion results are invalid if coordinate system is e.g. rotated. We need to implement new conversion functions that take into account all applied transformations and also convert x,y coordinates in one call because in general case x,y coordinates are coupled and cannot be converted independently on each other. Closes #18923. --- include/wx/dc.h | 16 +++++++++++ interface/wx/dc.h | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/include/wx/dc.h b/include/wx/dc.h index 41f6d8212e..6dcf24c1c3 100644 --- a/include/wx/dc.h +++ b/include/wx/dc.h @@ -1014,6 +1014,14 @@ public: { return m_pimpl->DeviceToLogicalXRel(x); } wxCoord DeviceToLogicalYRel(wxCoord y) const { return m_pimpl->DeviceToLogicalYRel(y); } + wxPoint DeviceToLogical(const wxPoint& pt) const + { return m_pimpl->DeviceToLogical(pt.x, pt.y); } + wxPoint DeviceToLogical(wxCoord x, wxCoord y) const + { return m_pimpl->DeviceToLogical(x, y); } + wxSize DeviceToLogicalRel(const wxSize& dim) const + { return m_pimpl->DeviceToLogicalRel(dim.x, dim.y); } + wxSize DeviceToLogicalRel(int x, int y) const + { return m_pimpl->DeviceToLogicalRel(x, y); } wxCoord LogicalToDeviceX(wxCoord x) const { return m_pimpl->LogicalToDeviceX(x); } wxCoord LogicalToDeviceY(wxCoord y) const @@ -1022,6 +1030,14 @@ public: { return m_pimpl->LogicalToDeviceXRel(x); } wxCoord LogicalToDeviceYRel(wxCoord y) const { return m_pimpl->LogicalToDeviceYRel(y); } + wxPoint LogicalToDevice(const wxPoint& pt) const + { return m_pimpl->LogicalToDevice(pt.x, pt.y); } + wxPoint LogicalToDevice(wxCoord x, wxCoord y) const + { return m_pimpl->LogicalToDevice(x, y); } + wxSize LogicalToDeviceRel(const wxSize& dim) const + { return m_pimpl->LogicalToDeviceRel(dim.x, dim.y); } + wxSize LogicalToDeviceRel(int x, int y) const + { return m_pimpl->LogicalToDeviceRel(x, y); } void SetMapMode(wxMappingMode mode) { m_pimpl->SetMapMode(mode); } diff --git a/interface/wx/dc.h b/interface/wx/dc.h index 10a0392df5..fc1505ec21 100644 --- a/interface/wx/dc.h +++ b/interface/wx/dc.h @@ -283,6 +283,74 @@ public: */ wxCoord LogicalToDeviceYRel(wxCoord y) const; + /** + Converts device (@a x, @a y) coordinates to logical coordinates + taking into account all apllied transformations like the current + mapping mode, scale factors, device origin, axes orientation, + affine transformation. + + @since 3.1.5 + */ + wxPoint DeviceToLogical(wxCoord x, wxCoord y) const; + + /** + @overload + + @since 3.1.5 + */ + wxPoint DeviceToLogical(const wxPoint& pt) const; + + /** + Converts device @a x, @a y coordinates to relative logical coordinates + taking into account all apllied transformations like the current + mapping mode, scale factors, affine transformation. + Use this for converting distances like e.g. width and height. + + @since 3.1.5 + */ + wxSize DeviceToLogicalRel(int x, int y) const; + + /** + @overload + + @since 3.1.5 + */ + wxSize DeviceToLogicalRel(const wxSize& dim) const; + + /** + Converts logical (@a x, @a y) coordinates to device coordinates + taking into account all apllied transformations like the current + mapping mode, scale factors, device origin, axes orientation, + affine transformation. + + @since 3.1.5 + */ + wxPoint LogicalToDevice(wxCoord x, wxCoord y) const; + + /** + @overload + + @since 3.1.5 + */ + wxPoint LogicalToDevice(const wxPoint& pt) const; + + /** + Converts logical @a x, @a y coordinates to relative device coordinates + taking into account all apllied transformations like the current + mapping mode, scale factors, affine transformation. + Use this for converting distances like e.g. width and height. + + @since 3.1.5 + */ + wxSize LogicalToDeviceRel(int x, int y) const; + + /** + @overload + + @since 3.1.5 + */ + wxSize LogicalToDeviceRel(const wxSize& dim) const; + //@} From d00ca6a1726c8f4ad00b4bb747c49b116bf4784c Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 27 Sep 2020 13:38:41 +0200 Subject: [PATCH 042/105] Add more unit tests of coordinates conversion functions --- tests/graphics/coords.cpp | 578 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 578 insertions(+) diff --git a/tests/graphics/coords.cpp b/tests/graphics/coords.cpp index 67e376ebcd..061900cf99 100644 --- a/tests/graphics/coords.cpp +++ b/tests/graphics/coords.cpp @@ -166,6 +166,33 @@ static void NoTransform(wxDC *dc) CHECK(dimDev.y == s_dimDev.y); } +static void NoTransformEx(wxDC * dc) +{ + // No transformations + + // First convert from device to logical coordinates + wxPoint posLog; + posLog = dc->DeviceToLogical(s_posDev); + CHECK(posLog.x == s_posDev.x); + CHECK(posLog.y == s_posDev.y); + + wxSize dimLog; + dimLog = dc->DeviceToLogicalRel(s_dimDev); + CHECK(dimLog.x == s_dimDev.x); + CHECK(dimLog.y == s_dimDev.y); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev = dc->LogicalToDevice(posLog); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev = dc->LogicalToDeviceRel(dimLog); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + static void DeviceOriginChanged(wxDC* dc) { // Only device origin is changed @@ -200,6 +227,36 @@ static void DeviceOriginChanged(wxDC* dc) CHECK(dimDev.y == s_dimDev.y); } +static void DeviceOriginChangedEx(wxDC * dc) +{ + // Only device origin is changed + const wxCoord dx = 10; + const wxCoord dy = 15; + dc->SetDeviceOrigin(dx, dy); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog = dc->DeviceToLogical(s_posDev); + CHECK(posLog.x == s_posDev.x - dx); + CHECK(posLog.y == s_posDev.y - dy); + + wxSize dimLog; + dimLog = dc->DeviceToLogicalRel(s_dimDev); + CHECK(dimLog.x == s_dimDev.x); + CHECK(dimLog.y == s_dimDev.y); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev = dc->LogicalToDevice(posLog); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev = dc->LogicalToDeviceRel(dimLog); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + static void LogicalOriginChanged(wxDC* dc) { // Only logical origin is changed @@ -234,6 +291,36 @@ static void LogicalOriginChanged(wxDC* dc) CHECK(dimDev.y == s_dimDev.y); } +static void LogicalOriginChangedEx(wxDC * dc) +{ + // Only logical origin is changed + const wxCoord dx = -15; + const wxCoord dy = -20; + dc->SetLogicalOrigin(dx, dy); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog = dc->DeviceToLogical(s_posDev); + CHECK(posLog.x == s_posDev.x + dx); + CHECK(posLog.y == s_posDev.y + dy); + + wxSize dimLog; + dimLog = dc->DeviceToLogicalRel(s_dimDev); + CHECK(dimLog.x == s_dimDev.x); + CHECK(dimLog.y == s_dimDev.y); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev = dc->LogicalToDevice(posLog); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev = dc->LogicalToDeviceRel(dimLog); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + static void UserScaleChanged(wxDC* dc) { // Only user scale is changed @@ -268,6 +355,36 @@ static void UserScaleChanged(wxDC* dc) CHECK(dimDev.y == s_dimDev.y); } +static void UserScaleChangedEx(wxDC * dc) +{ + // Only user scale is changed + const double sx = 2.0; + const double sy = 3.0; + dc->SetUserScale(sx, sy); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog = dc->DeviceToLogical(s_posDev); + CHECK(posLog.x == wxRound(s_posDev.x / sx)); + CHECK(posLog.y == wxRound(s_posDev.y / sy)); + + wxSize dimLog; + dimLog = dc->DeviceToLogicalRel(s_dimDev); + CHECK(dimLog.x == wxRound(s_dimDev.x / sx)); + CHECK(dimLog.y == wxRound(s_dimDev.y / sy)); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev = dc->LogicalToDevice(posLog); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev = dc->LogicalToDeviceRel(dimLog); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + static void LogicalScaleChanged(wxDC* dc) { // Only logical scale is changed @@ -302,6 +419,36 @@ static void LogicalScaleChanged(wxDC* dc) CHECK(dimDev.y == s_dimDev.y); } +static void LogicalScaleChangedEx(wxDC * dc) +{ + // Only logical scale is changed + const double sx = 2.0; + const double sy = 3.0; + dc->SetLogicalScale(sx, sy); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog = dc->DeviceToLogical(s_posDev); + CHECK(posLog.x == wxRound(s_posDev.x / sx)); + CHECK(posLog.y == wxRound(s_posDev.y / sy)); + + wxSize dimLog; + dimLog = dc->DeviceToLogicalRel(s_dimDev); + CHECK(dimLog.x == wxRound(s_dimDev.x / sx)); + CHECK(dimLog.y == wxRound(s_dimDev.y / sy)); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev = dc->LogicalToDevice(posLog); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev = dc->LogicalToDeviceRel(dimLog); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + static void TransformedStd(wxDC* dc) { // Apply all standardd transformations @@ -337,6 +484,37 @@ static void TransformedStd(wxDC* dc) CHECK(dimDev.y == s_dimDev.y); } +static void TransformedStdEx(wxDC * dc) +{ + // Apply all standardd transformations + dc->SetDeviceOrigin(10, 15); + dc->SetUserScale(0.5, 2.0); + dc->SetLogicalScale(4.0, 1.5); + dc->SetLogicalOrigin(-15, -20); + + // First convert from device to logical coordinates + wxPoint posLog; + posLog = dc->DeviceToLogical(s_posDev); + CHECK(posLog.x == -8); + CHECK(posLog.y == -6); + + wxSize dimLog; + dimLog = dc->DeviceToLogicalRel(s_dimDev); + CHECK(dimLog.x == 20); + CHECK(dimLog.y == 5); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev = dc->LogicalToDevice(posLog); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev = dc->LogicalToDeviceRel(dimLog); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); +} + static void TransformedWithMatrix(wxDC* dc) { // Apply transformation matrix only @@ -387,6 +565,46 @@ static void TransformedWithMatrix(wxDC* dc) #endif // wxUSE_DC_TRANSFORM_MATRIX } +static void TransformedWithMatrixEx(wxDC * dc) +{ + // Apply transformation matrix only +#if wxUSE_DC_TRANSFORM_MATRIX + if ( dc->CanUseTransformMatrix() ) + { + // Apply translation and scaling only + wxAffineMatrix2D m = dc->GetTransformMatrix(); + m.Translate(10, 15); + m.Scale(2.0, 3.0); + dc->SetTransformMatrix(m); + + // First convert from device to logical coordinates + m.Invert(); + wxPoint2DDouble posLogRef = m.TransformPoint(wxPoint2DDouble(s_posDev)); + wxPoint posLog; + posLog = dc->DeviceToLogical(s_posDev); + CHECK(posLog.x == wxRound(posLogRef.m_x)); + CHECK(posLog.y == wxRound(posLogRef.m_y)); + + wxPoint2DDouble dimLogRef = m.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y)); + wxSize dimLog; + dimLog = dc->DeviceToLogicalRel(s_dimDev); + CHECK(dimLog.x == wxRound(dimLogRef.m_x)); + CHECK(dimLog.y == wxRound(dimLogRef.m_y)); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev = dc->LogicalToDevice(posLog); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev = dc->LogicalToDeviceRel(dimLog); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); + } +#endif // wxUSE_DC_TRANSFORM_MATRIX +} + static void TransformedWithMatrixAndStd(wxDC* dc) { // Apply combination of standard and matrix transformations @@ -443,6 +661,56 @@ static void TransformedWithMatrixAndStd(wxDC* dc) #endif // wxUSE_DC_TRANSFORM_MATRIX } +static void TransformedWithMatrixAndStdEx(wxDC * dc) +{ + // Apply combination of standard and matrix transformations +#if wxUSE_DC_TRANSFORM_MATRIX + if ( dc->CanUseTransformMatrix() ) + { + dc->SetDeviceOrigin(10, 15); + + dc->SetUserScale(0.5, 1.5); + dc->SetLogicalScale(4.0, 2.0); + dc->SetLogicalOrigin(-15, -20); + + wxAffineMatrix2D m = dc->GetTransformMatrix(); + m.Translate(10, 18); + m.Scale(2.0, 0.5); + dc->SetTransformMatrix(m); + + // First convert from device to logical coordinates + wxAffineMatrix2D m1; + m1.Translate(10 - (-15) * (0.5 * 4.0), 15 - (-20) * (1.5 * 2.0)); + m1.Scale(0.5 * 4.0, 1.5 * 2.0); + m1.Concat(m); + m1.Invert(); + + wxPoint2DDouble posLogRef = m1.TransformPoint(wxPoint2DDouble(s_posDev)); + wxPoint posLog; + posLog = dc->DeviceToLogical(s_posDev); + CHECK(posLog.x == wxRound(posLogRef.m_x)); + CHECK(posLog.y == wxRound(posLogRef.m_y)); + + wxPoint2DDouble dimLogRef = m1.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y)); + wxSize dimLog; + dimLog = dc->DeviceToLogicalRel(s_dimDev); + CHECK(dimLog.x == wxRound(dimLogRef.m_x)); + CHECK(dimLog.y == wxRound(dimLogRef.m_y)); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev = dc->LogicalToDevice(posLog); + CHECK(posDev.x == s_posDev.x); + CHECK(posDev.y == s_posDev.y); + + wxSize dimDev; + dimDev = dc->LogicalToDeviceRel(dimLog); + CHECK(dimDev.x == s_dimDev.x); + CHECK(dimDev.y == s_dimDev.y); + } +#endif // wxUSE_DC_TRANSFORM_MATRIX +} + static void RotatedWithMatrix(wxDC* dc) { // Apply matrix transformations with rotation component @@ -493,6 +761,46 @@ static void RotatedWithMatrix(wxDC* dc) #endif // wxUSE_DC_TRANSFORM_MATRIX } +static void RotatedWithMatrixEx(wxDC * dc) +{ + // Apply matrix transformations with rotation component +#if wxUSE_DC_TRANSFORM_MATRIX + if ( dc->CanUseTransformMatrix() ) + { + wxAffineMatrix2D m = dc->GetTransformMatrix(); + m.Rotate(6 * M_PI / 180.0); + m.Translate(10, 15); + m.Scale(2.0, 3.0); + dc->SetTransformMatrix(m); + + // First convert from device to logical coordinates + m.Invert(); + wxPoint2DDouble posLogRef = m.TransformPoint(wxPoint2DDouble(s_posDev)); + wxPoint posLog; + posLog = dc->DeviceToLogical(s_posDev); + CHECK(posLog.x == wxRound(posLogRef.m_x)); + CHECK(posLog.y == wxRound(posLogRef.m_y)); + + wxPoint2DDouble dimLogRef = m.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y)); + wxSize dimLog; + dimLog = dc->DeviceToLogicalRel(s_dimDev); + CHECK(dimLog.x == wxRound(dimLogRef.m_x)); + CHECK(dimLog.y == wxRound(dimLogRef.m_y)); + + // And next back from logical to device coordinates + wxPoint posDev; + posDev = dc->LogicalToDevice(posLog); + CHECK(Approx(posDev.x).margin(1) == s_posDev.x); + CHECK(Approx(posDev.y).margin(1) == s_posDev.y); + + wxSize dimDev; + dimDev = dc->LogicalToDeviceRel(dimLog); + CHECK(Approx(dimDev.x).margin(1) == s_dimDev.x); + CHECK(Approx(dimDev.y).margin(1) == s_dimDev.y); + } +#endif // wxUSE_DC_TRANSFORM_MATRIX +} + // For GTK+ 3 and OSX wxDC is equivalent to wxGCDC // so it doesn't need to be tested individually. #if !defined(__WXGTK3__) && !defined(__WXOSX__) @@ -508,53 +816,107 @@ TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::NoTransform", "[coordina NoTransform(m_dc); } +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::NoTransformEx", "[coordinates]") +{ + // No transformations + NoTransformEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::DeviceOriginChanged", "[coordinates]") { // Only device origin is changed DeviceOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::DeviceOriginChangedEx", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalOriginChanged", "[coordinates]") { // Only logical origin is changed LogicalOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalOriginChangedEx", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::UserScaleChanged", "[coordinates]") { // Only user scale is changed UserScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::UserScaleChangedEx", "[coordinates]") +{ + // Only user scale is changed + UserScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalScaleChanged", "[coordinates]") { // Only logical scale is changed LogicalScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalScaleChangedEx", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedStd", "[coordinates]") { // Apply all standardd transformations TransformedStd(m_dc); } +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedStdEx", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrix", "[coordinates]") { // Apply transformation matrix only TransformedWithMatrix(m_dc); } +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrixEx", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrixEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrixAndStd", "[coordinates]") { // Apply combination of standard and matrix transformations TransformedWithMatrixAndStd(m_dc); } +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrixAndStdEx", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::RotatedWithMatrix", "[coordinates]") { // Apply matrix transformations with rotation component RotatedWithMatrix(m_dc); } + +TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::RotatedWithMatrixEx", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrixEx(m_dc); +} #endif // !__WXGTK3__ && !_WXOSX__ #if wxUSE_GRAPHICS_CONTEXT @@ -573,53 +935,107 @@ TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::NoTransform", "[coor NoTransform(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::NoTransformEx", "[coordinates]") +{ + // No transformations + NoTransformEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::DeviceOriginChanged", "[coordinates]") { // Only device origin is changed DeviceOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::DeviceOriginChangedEx", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalOriginChanged", "[coordinates]") { // Only logical origin is changed LogicalOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalOriginChangedEx", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::UserScaleChanged", "[coordinates]") { // Only user scale is changed UserScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::UserScaleChangedEx", "[coordinates]") +{ + // Only user scale is changed + UserScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalScaleChanged", "[coordinates]") { // Only logical scale is changed LogicalScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalScaleChangedEx", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedStd", "[coordinates]") { // Apply all standardd transformations TransformedStd(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedStdEx", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrix", "[coordinates]") { // Apply transformation matrix only TransformedWithMatrix(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrixEx", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrixEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrixAndStd", "[coordinates]") { // Apply combination of standard and matrix transformations TransformedWithMatrixAndStd(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrixAndStdEx", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::RotatedWithMatrix", "[coordinates]") { // Apply matrix transformations with rotation component RotatedWithMatrix(m_dc); } + +TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::RotatedWithMatrixEx", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrixEx(m_dc); +} #else// GDI+ and Direct2D are available only under MSW. #if wxUSE_GRAPHICS_GDIPLUS class CoordinatesGCDCGDIPlusTestCase : public CoordinatesGCDCTestCase @@ -648,53 +1064,107 @@ TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::NoTran NoTransform(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::NoTransformEx", "[coordinates]") +{ + // No transformations + NoTransformEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::DeviceOriginChanged", "[coordinates]") { // Only device origin is changed DeviceOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::DeviceOriginChangedEx", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalOriginChanged", "[coordinates]") { // Only logical origin is changed LogicalOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalOriginChangedEx", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::UserScaleChanged", "[coordinates]") { // Only user scale is changed UserScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::UserScaleChangedEx", "[coordinates]") +{ + // Only user scale is changed + UserScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalScaleChanged", "[coordinates]") { // Only logical scale is changed LogicalScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalScaleChangedex", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedStd", "[coordinates]") { // Apply all standardd transformations TransformedStd(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedStdEx", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrix", "[coordinates]") { // Apply transformation matrix only TransformedWithMatrix(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrixEx", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrixEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrixAndStd", "[coordinates]") { // Apply combination of standard and matrix transformations TransformedWithMatrixAndStd(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrixAndStdEx", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::RotatedWithMatrix", "[coordinates]") { // Apply matrix transformations with rotation component RotatedWithMatrix(m_dc); } + +TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::RotatedWithMatrixEx", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrixEx(m_dc); +} #endif // wxUSE_GRAPHICS_GDIPLUS #if wxUSE_GRAPHICS_DIRECT2D @@ -724,53 +1194,107 @@ TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::NoTr NoTransform(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::NoTransformEx", "[coordinates]") +{ + // No transformations + NoTransformEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::DeviceOriginChanged", "[coordinates]") { // Only device origin is changed DeviceOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::DeviceOriginChangedEx", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalOriginChanged", "[coordinates]") { // Only logical origin is changed LogicalOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalOriginChangedEx", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::UserScaleChanged", "[coordinates]") { // Only user scale is changed UserScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::UserScaleChangedEx", "[coordinates]") +{ + // Only user scale is changed + UserScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalScaleChanged", "[coordinates]") { // Only logical scale is changed LogicalScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalScaleChangedEx", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedStd", "[coordinates]") { // Apply all standardd transformations TransformedStd(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedStdEx", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrix", "[coordinates]") { // Apply transformation matrix only TransformedWithMatrix(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrixEx", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrixEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrixAndStd", "[coordinates]") { // Apply combination of standard and matrix transformations TransformedWithMatrixAndStd(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrixAndStdEx", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::RotatedWithMatrix", "[coordinates]") { // Apply matrix transformations with rotation component RotatedWithMatrix(m_dc); } + +TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::RotatedWithMatrixEx", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrixEx(m_dc); +} #endif // wxUSE_GRAPHICS_DIRECT2D #endif // __WXMSW__/!__WXMSW__ @@ -801,52 +1325,106 @@ TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::NoTransfor NoTransform(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::NoTransformEx", "[coordinates]") +{ + // No transformations + NoTransformEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::DeviceOriginChanged", "[coordinates]") { // Only device origin is changed DeviceOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::DeviceOriginChangedEx", "[coordinates]") +{ + // Only device origin is changed + DeviceOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalOriginChanged", "[coordinates]") { // Only logical origin is changed LogicalOriginChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalOriginChangedEx", "[coordinates]") +{ + // Only logical origin is changed + LogicalOriginChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::UserScaleChanged", "[coordinates]") { // Only user scale is changed UserScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::UserScaleChangedEx", "[coordinates]") +{ + // Only user scale is changed + UserScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalScaleChanged", "[coordinates]") { // Only logical scale is changed LogicalScaleChanged(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalScaleChangedEx", "[coordinates]") +{ + // Only logical scale is changed + LogicalScaleChangedEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedStd", "[coordinates]") { // Apply all standardd transformations TransformedStd(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedStdEx", "[coordinates]") +{ + // Apply all standardd transformations + TransformedStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrix", "[coordinates]") { // Apply transformation matrix only TransformedWithMatrix(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrixEx", "[coordinates]") +{ + // Apply transformation matrix only + TransformedWithMatrixEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrixAndStd", "[coordinates]") { // Apply combination of standard and matrix transformations TransformedWithMatrixAndStd(m_dc); } +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrixAndStdEx", "[coordinates]") +{ + // Apply combination of standard and matrix transformations + TransformedWithMatrixAndStdEx(m_dc); +} + TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::RotatedWithMatrix", "[coordinates]") { // Apply matrix transformations with rotation component RotatedWithMatrix(m_dc); } + +TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::RotatedWithMatrixEx", "[coordinates]") +{ + // Apply matrix transformations with rotation component + RotatedWithMatrixEx(m_dc); +} #endif // wxUSE_CAIRO #endif // wxUSE_GRAPHICS_CONTEXT From 2f679396fddf946f6cfb1ac8f03976024cf157ba Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 27 Sep 2020 13:58:01 +0200 Subject: [PATCH 043/105] Fix typo in documentation --- interface/wx/dc.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/wx/dc.h b/interface/wx/dc.h index fc1505ec21..e5af4c2491 100644 --- a/interface/wx/dc.h +++ b/interface/wx/dc.h @@ -285,7 +285,7 @@ public: /** Converts device (@a x, @a y) coordinates to logical coordinates - taking into account all apllied transformations like the current + taking into account all applied transformations like the current mapping mode, scale factors, device origin, axes orientation, affine transformation. @@ -302,7 +302,7 @@ public: /** Converts device @a x, @a y coordinates to relative logical coordinates - taking into account all apllied transformations like the current + taking into account all applied transformations like the current mapping mode, scale factors, affine transformation. Use this for converting distances like e.g. width and height. @@ -319,7 +319,7 @@ public: /** Converts logical (@a x, @a y) coordinates to device coordinates - taking into account all apllied transformations like the current + taking into account all applied transformations like the current mapping mode, scale factors, device origin, axes orientation, affine transformation. @@ -336,7 +336,7 @@ public: /** Converts logical @a x, @a y coordinates to relative device coordinates - taking into account all apllied transformations like the current + taking into account all applied transformations like the current mapping mode, scale factors, affine transformation. Use this for converting distances like e.g. width and height. From 6a1e3fa232e511751bd94e77eb38e34dd40a3619 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Mon, 21 Sep 2020 21:16:07 +0200 Subject: [PATCH 044/105] Improve the introduction to the high DPI overview Add images to show the difference between scaled text and text rendered at the full resolution. --- .../images/overview_highdpi_text_144.png | Bin 0 -> 21384 bytes .../images/overview_highdpi_text_72.png | Bin 0 -> 17212 bytes docs/doxygen/overviews/high_dpi.md | 70 +++++++++++------- 3 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 docs/doxygen/images/overview_highdpi_text_144.png create mode 100644 docs/doxygen/images/overview_highdpi_text_72.png diff --git a/docs/doxygen/images/overview_highdpi_text_144.png b/docs/doxygen/images/overview_highdpi_text_144.png new file mode 100644 index 0000000000000000000000000000000000000000..10d430d7b932a6d8116f559017dd838ca695eba3 GIT binary patch literal 21384 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 G_SetClientSize(myFrame->FromDIP(wxSize(400, 300))); ``` - Physical Pixels -=============== +--------------- In addition to (logical) pixels and DIPs discussed above, you may also need to work in physical pixel coordinates, corresponding to the actual display pixels. @@ -88,6 +100,8 @@ For example, in a wxGLCanvas created with the size of 100 (logical) pixels, the rightmost physical pixel coordinate will be `100*GetContentScaleFactor()`. +[comment]: # (TODO: High-Resolution Images and Artwork) + Platform-Specific Build Issues ============================== @@ -104,12 +118,12 @@ MSW The behaviour of the application when running on a high-DPI display depends on the values in its [manifest][1]. If your application include `wx/msw/wx.rc` from its resource file, you need to predefine `wxUSE_DPI_AWARE_MANIFEST` to -opt-in into high DPI support: define it as `1` for minimal DPI awareness and +opt-in into [high DPI support][2]: define it as `1` for minimal DPI awareness and `2` for full, per-monitor DPI awareness supported by Windows 10 version 1703 or later. [1]: https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests - +[2]: https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows macOS ----- From ba547496f9738b14f5efe3442a17835c66e6d4c4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 28 Sep 2020 01:57:41 +0200 Subject: [PATCH 045/105] Minor edit to the high DPI overview Provide some link between the end of the introduction and the main part of the text. --- docs/doxygen/overviews/high_dpi.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/doxygen/overviews/high_dpi.md b/docs/doxygen/overviews/high_dpi.md index a31f1ed8c0..db25a9c4c7 100644 --- a/docs/doxygen/overviews/high_dpi.md +++ b/docs/doxygen/overviews/high_dpi.md @@ -44,11 +44,14 @@ would become 1000 when automatic scaling is in effect. Automatic scaling is convenient, but doesn't really allow the application to use the extra pixels available on the display. Visually, this means that the scaled application appears blurry, in contrast to sharper applications using -the full display resolution, so a better solution is needed. +the full display resolution, so a better solution for interpreting pixel values +on high DPI displays is needed: one which allows to scale some pixel values +(e.g. the total window size), but not some other ones (e.g. those used for +drawing, which should remain unscaled to use the full available resolution). -Pixel Values in High DPI -======================== +Pixel Values in wxWidgets +========================= Logical and Device-Independent Pixels ------------------------------------- From daa6eca2e74a002c544ff6eeda96c02865dfb0fa Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 28 Sep 2020 02:56:19 +0200 Subject: [PATCH 046/105] Skip AppVeyor builds when GitHub workflows are modified Don't waste AppVeyor CI resources unnecessarily. --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index 0c75abc35b..0b43c6da5c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,6 +12,7 @@ skip_commits: - misc/ - include/wx/osx/ - src/osx/ + - .github/workflows/ - .travis.yml - build/tools/travis-ci.sh - build/tools/before_install.sh From 5358dd70076dc56989dacd884ed047b4b3e2657c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 28 Sep 2020 02:43:26 +0200 Subject: [PATCH 047/105] Add a check for trailing whitespace and TABs Just use Git itself to check for it in the new files. --- .github/workflows/code_checks.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/code_checks.yml b/.github/workflows/code_checks.yml index 121701be0b..85191fa9c4 100644 --- a/.github/workflows/code_checks.yml +++ b/.github/workflows/code_checks.yml @@ -41,3 +41,22 @@ jobs: - name: Run codespell run: | CODESPELL=$HOME/.local/bin/codespell ./misc/scripts/spellcheck + + + check-whitespace: + runs-on: ubuntu-20.04 + name: Check Whitespace + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Check for trailing whitespace and TABs + run: | + git fetch --depth=1 origin master + git -c core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol,tab-in-indent \ + diff --check origin/master '*' \ + '!**/*akefile*' \ + '!**/*.sln' \ + '!**/*.vcproj' \ + '!**/*.xpm' From bf7965a2d7b7a14a3c93a9813650ab23b7a2f47d Mon Sep 17 00:00:00 2001 From: Ian McInerney Date: Mon, 28 Sep 2020 02:33:30 +0100 Subject: [PATCH 048/105] Add null check in wxAuiToolBar event handler This also prevents the AUI_TOOLBAR_BEGIN_DRAG event from being sent if there is no active toolbar item being dragged. Closes https://github.com/wxWidgets/wxWidgets/pull/2062 --- src/aui/auibar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aui/auibar.cpp b/src/aui/auibar.cpp index b07b2ca296..72ee06218d 100644 --- a/src/aui/auibar.cpp +++ b/src/aui/auibar.cpp @@ -2839,7 +2839,7 @@ void wxAuiToolBar::OnMotion(wxMouseEvent& evt) const bool button_pressed = HasCapture(); // start a drag event - if (!m_dragging && button_pressed && + if (!m_dragging && button_pressed && m_actionItem && abs(evt.GetX() - m_actionPos.x) + abs(evt.GetY() - m_actionPos.y) > 5) { // TODO: sending this event only makes sense if there is an 'END_DRAG' From d9deaa8b76128613a84f3d085eb1e4b05631083a Mon Sep 17 00:00:00 2001 From: Thomas Khyn Date: Fri, 25 Sep 2020 20:33:59 +1200 Subject: [PATCH 049/105] Allow CMake dependencies to be interfaces In some cases (see https://github.com/bincrafters/community/issues/1181), the dependencies can be library interfaces. As CMake's get_target_property is not tolerant about what properties can be extracted on different library types, it is necessary to make a distinction between interface libraries and plain libraries. Closes https://github.com/wxWidgets/wxWidgets/pull/2058 --- build/cmake/config.cmake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build/cmake/config.cmake b/build/cmake/config.cmake index 6978cc2725..15dff884ea 100644 --- a/build/cmake/config.cmake +++ b/build/cmake/config.cmake @@ -33,7 +33,12 @@ macro(wx_get_dependencies var lib) get_target_property(deps wx${lib} LINK_LIBRARIES) foreach(dep IN LISTS deps) if(TARGET ${dep}) - get_target_property(dep_name ${dep} OUTPUT_NAME) + get_target_property(dep_type ${dep} TYPE) + if (dep_type STREQUAL "INTERFACE_LIBRARY") + get_target_property(dep_name ${dep} INTERFACE_OUTPUT_NAME) + else() + get_target_property(dep_name ${dep} OUTPUT_NAME) + endif() set(dep_name "-l${dep_name}") else() get_filename_component(dep_name ${dep} NAME) From 56521ad8af538d1ced8bf9a986cdabf1bb962b04 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Tue, 29 Sep 2020 00:09:46 +0200 Subject: [PATCH 050/105] CMake: add missing test files Add the source files present in the bkl but not CMakeLists.txt to the latter one too. Also link with AUI library now that a test file using it is included. Closes https://github.com/wxWidgets/wxWidgets/pull/2064 --- build/cmake/tests/gui/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/cmake/tests/gui/CMakeLists.txt b/build/cmake/tests/gui/CMakeLists.txt index c0f62ff77e..61cc082cc6 100644 --- a/build/cmake/tests/gui/CMakeLists.txt +++ b/build/cmake/tests/gui/CMakeLists.txt @@ -22,9 +22,11 @@ set(TEST_GUI_SRC graphics/affinematrix.cpp graphics/boundingbox.cpp graphics/clippingbox.cpp + graphics/coords.cpp graphics/graphmatrix.cpp graphics/graphpath.cpp config/config.cpp + controls/auitest.cpp controls/bitmapcomboboxtest.cpp controls/bitmaptogglebuttontest.cpp controls/bookctrlbasetest.cpp @@ -102,11 +104,13 @@ set(TEST_GUI_SRC net/socket.cpp persistence/tlw.cpp persistence/dataview.cpp + rowheightcache/rowheightcachetest.cpp sizers/boxsizer.cpp sizers/gridsizer.cpp sizers/wrapsizer.cpp toplevel/toplevel.cpp validators/valnum.cpp + validators/valtext.cpp window/clientsize.cpp window/setsize.cpp xml/xrctest.cpp @@ -169,6 +173,9 @@ wx_add_test(test_gui ${TEST_GUI_SRC} RES ../samples/sample.rc ) wx_exe_link_libraries(test_gui wxcore) +if(wxUSE_AUI) + wx_exe_link_libraries(test_gui wxaui) +endif() if(wxUSE_RICHTEXT) wx_exe_link_libraries(test_gui wxrichtext) endif() From 9aa5eb9c5389fb7a944ccd950a2a1ba658639a13 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Mon, 28 Sep 2020 08:26:04 +0200 Subject: [PATCH 051/105] Add beginning of the artwork paragraph This will be fleshed out later. --- docs/doxygen/overviews/high_dpi.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/doxygen/overviews/high_dpi.md b/docs/doxygen/overviews/high_dpi.md index db25a9c4c7..9770a232d2 100644 --- a/docs/doxygen/overviews/high_dpi.md +++ b/docs/doxygen/overviews/high_dpi.md @@ -103,8 +103,19 @@ For example, in a wxGLCanvas created with the size of 100 (logical) pixels, the rightmost physical pixel coordinate will be `100*GetContentScaleFactor()`. -[comment]: # (TODO: High-Resolution Images and Artwork) +High-Resolution Images and Artwork +================================== +In order to benefit from the increased detail on High DPI devices you might want +to provide the images or artwork your application uses in higher resolutions as +well. Note that it is not recommended to just provide a high-resolution version +and let the system scale that down on 1x displays. Apart from performance +consideration also the quality might suffer, contours become more blurry. + +You can use vector based graphics like SVG or you can add the same image at different +sizes / resolutions. + +[comment]: # (TODO: API and Use Cases) Platform-Specific Build Issues ============================== From 1f0ade29f05c9a1413532a894810b7550deb9392 Mon Sep 17 00:00:00 2001 From: Eric Raijmakers Date: Wed, 30 Sep 2020 12:09:23 +0200 Subject: [PATCH 052/105] Fix using mask colour even if there is no mask in wxImage::Paste In case an image without alpha is pasted on top of an image with alpha, the alpha blending gives wrong results. This is caused by the fact that the final (if nothing has been pasted yet) pixel copying algorithm in Paste() does not take into account whether the pasted image actually uses a mask. To fix this: - Add the check for image.HasMask(). - In case there is no mask, simply copy the image via memcpy. - Finally, update the alpha channel of the changed image (if present): whenever a pixel is copied, the alpha is set to fully opaque. Closes https://github.com/wxWidgets/wxWidgets/pull/2065 --- src/common/image.cpp | 64 ++++++++++++++++------ tests/image/image.cpp | 87 +++++++++++++++++++++++++++--- tests/image/paste_input_black.png | Bin 0 -> 150 bytes 3 files changed, 127 insertions(+), 24 deletions(-) create mode 100644 tests/image/paste_input_black.png diff --git a/src/common/image.cpp b/src/common/image.cpp index 8d935a1cfb..8515cf4c3a 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -1739,29 +1739,61 @@ wxImage::Paste(const wxImage & image, int x, int y, // being pasted into account. if (!copiedPixels) { - unsigned char r = image.GetMaskRed(); - unsigned char g = image.GetMaskGreen(); - unsigned char b = image.GetMaskBlue(); + const unsigned char* source_data = image.GetData() + 3 * (xx + yy * image.GetWidth()); + int source_step = image.GetWidth() * 3; - const unsigned char* source_data = image.GetData() + 3*(xx + yy*image.GetWidth()); - int source_step = image.GetWidth()*3; + unsigned char* target_data = GetData() + 3 * ((x + xx) + (y + yy) * M_IMGDATA->m_width); + int target_step = M_IMGDATA->m_width * 3; - unsigned char* target_data = GetData() + 3*((x+xx) + (y+yy)*M_IMGDATA->m_width); - int target_step = M_IMGDATA->m_width*3; - - for (int j = 0; j < height; j++) + unsigned char* alpha_target_data = NULL; + const int target_alpha_step = M_IMGDATA->m_width; + if (HasAlpha()) { - for (int i = 0; i < width*3; i+=3) + alpha_target_data = GetAlpha() + (x + xx) + (y + yy) * M_IMGDATA->m_width; + } + + // The mask colours should only be taken into account if the mask is actually enabled + if (!image.HasMask()) + { + // Copy all pixels + for (int j = 0; j < height; j++) { - if ((source_data[i] != r) || - (source_data[i+1] != g) || - (source_data[i+2] != b)) + memcpy(target_data, source_data, width * 3); + source_data += source_step; + target_data += target_step; + // Make all the copied pixels fully opaque + if (alpha_target_data != NULL) { - memcpy( target_data+i, source_data+i, 3 ); + memset(alpha_target_data, wxALPHA_OPAQUE, target_alpha_step); + alpha_target_data += target_alpha_step; } } - source_data += source_step; - target_data += target_step; + } + else + { + // Copy all 'non masked' pixels + unsigned char r = image.GetMaskRed(); + unsigned char g = image.GetMaskGreen(); + unsigned char b = image.GetMaskBlue(); + + for (int j = 0; j < height; j++) + { + for (int i = 0; i < width * 3; i += 3) + { + if ((source_data[i] != r) || + (source_data[i + 1] != g) || + (source_data[i + 2] != b)) + { + // Copy the non masked pixel + memcpy(target_data + i, source_data + i, 3); + // Make the copied pixel fully opaque + alpha_target_data[i / 3] = wxALPHA_OPAQUE; + } + } + source_data += source_step; + target_data += target_step; + alpha_target_data += target_alpha_step; + } } } } diff --git a/tests/image/image.cpp b/tests/image/image.cpp index aa67d7678f..3672a31ff5 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -1460,7 +1460,7 @@ TEST_CASE("wxImage::Paste", "[image][paste]") { "9 9 7 1", " c None", - "y c #FF0000", + "y c #FFFF00", "r c #FF0000", "g c #00FF00", "b c #0000FF", @@ -1481,7 +1481,7 @@ TEST_CASE("wxImage::Paste", "[image][paste]") { "9 9 2 1", " c None", - "y c #FF0000", + "y c #FFFF00", "y y y y y", " y y y y ", "y y y y y", @@ -1508,7 +1508,7 @@ TEST_CASE("wxImage::Paste", "[image][paste]") { "13 13 2 1", " c None", - "y c #FF0000", + "y c #FFFF00", "y y y y y y y", " y y y y y y ", "y y y y y y y", @@ -1537,7 +1537,7 @@ TEST_CASE("wxImage::Paste", "[image][paste]") { "5 5 2 1", " c None", - "y c #FF0000", + "y c #FFFF00", "y y y", " y y ", "y y y", @@ -1549,7 +1549,7 @@ TEST_CASE("wxImage::Paste", "[image][paste]") { "9 9 7 1", " c None", - "y c #FF0000", + "y c #FFFF00", "r c #FF0000", "g c #00FF00", "b c #0000FF", @@ -1579,7 +1579,7 @@ TEST_CASE("wxImage::Paste", "[image][paste]") { "9 9 7 1", " c None", - "y c #FF0000", + "y c #FFFF00", "r c #FF0000", "g c #00FF00", "b c #0000FF", @@ -1609,7 +1609,7 @@ TEST_CASE("wxImage::Paste", "[image][paste]") { "9 9 7 1", " c None", - "y c #FF0000", + "y c #FFFF00", "r c #FF0000", "g c #00FF00", "b c #0000FF", @@ -1667,7 +1667,7 @@ TEST_CASE("wxImage::Paste", "[image][paste]") { "9 9 7 1", " c None", - "y c #FF0000", + "y c #FFFF00", "r c #FF0000", "g c #00FF00", "b c #0000FF", @@ -1768,6 +1768,77 @@ TEST_CASE("wxImage::Paste", "[image][paste]") CHECK_THAT(actual, RGBSimilarTo(wxImage("image/paste_result_no_background_square_over_circle.png"), 1)); CHECK_THAT(actual, CenterAlphaPixelEquals(224)); } + SECTION("Paste fully transparent (masked) image over light image") // todo make test case for 'blend with mask' + { + const static char* transparent_image_xpm[] = + { + "5 5 2 1", + " c None", // Mask + "y c #FFFF00", + " ", + " ", + " ", + " ", + " ", + }; + const static char* light_image_xpm[] = + { + "5 5 2 1", + " c None", + "y c #FFFF00", + "yyyyy", + "yyyyy", + "yyyyy", + "yyyyy", + "yyyyy", + }; + wxImage actual(light_image_xpm); + actual.InitAlpha(); + wxImage paste(transparent_image_xpm); + wxImage expected(light_image_xpm); + actual.Paste(paste, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSameAs(expected)); + } + SECTION("Paste fully black (masked) image over light image") // todo make test case for 'blend with mask' + { + const static char* black_image_xpm[] = + { + "5 5 2 1", + " c #000000", + "y c None", // Mask + " ", + " ", + " ", + " ", + " ", + }; + const static char* light_image_xpm[] = + { + "5 5 2 1", + " c None", + "y c #FFFF00", + "yyyyy", + "yyyyy", + "yyyyy", + "yyyyy", + "yyyyy", + }; + wxImage actual(light_image_xpm); + actual.InitAlpha(); + wxImage paste(black_image_xpm); + wxImage expected(black_image_xpm); + actual.Paste(paste, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSameAs(expected)); + } + SECTION("Paste dark image over light image") + { + wxImage black("image/paste_input_black.png"); + wxImage actual("image/paste_input_background.png"); + actual.InitAlpha(); + actual.Paste(black, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, CenterAlphaPixelEquals(255)); + CHECK_THAT(actual, RGBSameAs(black)); + } } /* diff --git a/tests/image/paste_input_black.png b/tests/image/paste_input_black.png new file mode 100644 index 0000000000000000000000000000000000000000..43f4668bba84b12d117391106779f52314d5d9db GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^DIm!lvI6O>_%)r2R5QG_bOw4`@6qNCFaSVw#{PrLtFOYX= j!FT^$es&fhlR;($qwpIB#salh8X&HxtDnm{r-UW| Date: Wed, 23 Sep 2020 03:01:02 -0500 Subject: [PATCH 053/105] Implement GetStringSelection() in generic wxBitmapComboBox Also update the test to avoid assuming that wxBitmapComboBox inherits from wxComboBox, which now allows it to build (and pass) on all platforms. Closes https://github.com/wxWidgets/wxWidgets/pull/2057 --- include/wx/generic/bmpcbox.h | 2 ++ src/generic/bmpcboxg.cpp | 5 +++++ tests/controls/bitmapcomboboxtest.cpp | 15 +++++++-------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/include/wx/generic/bmpcbox.h b/include/wx/generic/bmpcbox.h index 90a6ba4351..058a389ad9 100644 --- a/include/wx/generic/bmpcbox.h +++ b/include/wx/generic/bmpcbox.h @@ -84,6 +84,8 @@ public: virtual ~wxBitmapComboBox(); + virtual wxString GetStringSelection() const wxOVERRIDE; + // Adds item with image to the end of the combo box. int Append(const wxString& item, const wxBitmap& bitmap = wxNullBitmap); int Append(const wxString& item, const wxBitmap& bitmap, void *clientData); diff --git a/src/generic/bmpcboxg.cpp b/src/generic/bmpcboxg.cpp index 6432bccaf0..1e3bfff452 100644 --- a/src/generic/bmpcboxg.cpp +++ b/src/generic/bmpcboxg.cpp @@ -135,6 +135,11 @@ wxBitmapComboBox::~wxBitmapComboBox() DoClear(); } +wxString wxBitmapComboBox::GetStringSelection() const +{ + return wxItemContainer::GetStringSelection(); +} + // ---------------------------------------------------------------------------- // Item manipulation // ---------------------------------------------------------------------------- diff --git a/tests/controls/bitmapcomboboxtest.cpp b/tests/controls/bitmapcomboboxtest.cpp index 2a011b3869..904eb6079f 100644 --- a/tests/controls/bitmapcomboboxtest.cpp +++ b/tests/controls/bitmapcomboboxtest.cpp @@ -24,9 +24,6 @@ #include "itemcontainertest.h" #include "asserthelper.h" -//Test only if we are based off of wxComboBox -#ifndef wxGENERIC_BITMAPCOMBOBOX - class BitmapComboBoxTestCase : public TextEntryTestCase, public ItemContainerTestCase, public CppUnit::TestCase @@ -82,9 +79,9 @@ void BitmapComboBoxTestCase::Bitmap() wxArrayString items; items.push_back("item 0"); items.push_back("item 1"); - - //We need this otherwise MSVC complains as it cannot find a suitable append - static_cast(m_combo)->Append(items); + // TODO: Add wxBitmapComboBoxBase::Append(wxArrayString ) + for( unsigned int i = 0; i < items.size(); ++i ) + m_combo->Append(items[i]); CPPUNIT_ASSERT(!m_combo->GetItemBitmap(0).IsOk()); @@ -104,8 +101,10 @@ void BitmapComboBoxTestCase::Bitmap() CPPUNIT_ASSERT(m_combo->GetItemBitmap(0).IsOk()); CPPUNIT_ASSERT_EQUAL(wxSize(16, 16), m_combo->GetBitmapSize()); + + m_combo->SetSelection( 1 ); + + CPPUNIT_ASSERT_EQUAL( m_combo->GetStringSelection(), "item with bitmap" ); } -#endif //wxGENERIC_BITMAPCOMBOBOX - #endif //wxUSE_BITMAPCOMBOBOX From 88f808e303c1649a4ffdeb7044b1a5dd96e6e1d3 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 1 Oct 2020 02:28:42 +0200 Subject: [PATCH 054/105] Add a unit test for wxCaret::Create() Verify that constructing wxCaret using its default ctor and Create() works too, now that it does -- previously it uses to result in a GTK warning and a crash in wxGTK. --- tests/controls/windowtest.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/controls/windowtest.cpp b/tests/controls/windowtest.cpp index 372317e67b..cfcc4a0f6d 100644 --- a/tests/controls/windowtest.cpp +++ b/tests/controls/windowtest.cpp @@ -136,10 +136,22 @@ TEST_CASE_METHOD(WindowTestCase, "Window::Mouse", "[window]") CHECK(m_window->GetCursor().IsOk()); #if wxUSE_CARET - //A plain window doesn't have a caret CHECK(!m_window->GetCaret()); - wxCaret* caret = new wxCaret(m_window, 16, 16); + wxCaret* caret; + + // Try creating the caret in two different, but normally equivalent, ways. + SECTION("Caret 1-step") + { + caret = new wxCaret(m_window, 16, 16); + } + + SECTION("Caret 2-step") + { + caret = new wxCaret(); + caret->Create(m_window, 16, 16); + } + m_window->SetCaret(caret); CHECK(m_window->GetCaret()->IsOk()); From 204d8a45368cea504fef980bb9c8fb017d2461dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Thu, 1 Oct 2020 05:01:53 +0200 Subject: [PATCH 055/105] Add missing wxRibbonMSWArtProvider::GetButtonBarButtonTextWidth interface The missing override in the interface makes the inherited classes abstract from the Phoenix SIP generators view. --- interface/wx/ribbon/art.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/wx/ribbon/art.h b/interface/wx/ribbon/art.h index 167f440c3a..d551f3466f 100644 --- a/interface/wx/ribbon/art.h +++ b/interface/wx/ribbon/art.h @@ -1251,6 +1251,12 @@ public: wxRect* normal_region, wxRect* dropdown_region); + wxCoord GetButtonBarButtonTextWidth( + wxDC& dc, + const wxString& label, + wxRibbonButtonKind kind, + wxRibbonButtonBarButtonState size); + wxSize GetMinimisedPanelMinimumSize( wxDC& dc, const wxRibbonPanel* wnd, From 0c3494592aef7e0cad13410993b21d70f57e37ca Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Thu, 1 Oct 2020 17:47:12 +0200 Subject: [PATCH 056/105] Fix calculating mouse position in drawing sample Displayed logical mouse position was improper for rotated wxDC. --- samples/drawing/drawing.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/samples/drawing/drawing.cpp b/samples/drawing/drawing.cpp index acd2eeaa47..a278e6a204 100644 --- a/samples/drawing/drawing.cpp +++ b/samples/drawing/drawing.cpp @@ -2013,11 +2013,9 @@ void MyCanvas::OnMouseMove(wxMouseEvent &event) PrepareDC(dc); m_owner->PrepareDC(dc); - wxPoint pos = event.GetPosition(); - long x = dc.DeviceToLogicalX( pos.x ); - long y = dc.DeviceToLogicalY( pos.y ); + wxPoint pos = dc.DeviceToLogical(event.GetPosition()); wxString str; - str.Printf( "Current mouse position: %d,%d", (int)x, (int)y ); + str.Printf( "Current mouse position: %d,%d", pos.x, pos.y ); m_owner->SetStatusText( str ); } From ec8bfbebdc74b07794ae607378e3e04a57e82f80 Mon Sep 17 00:00:00 2001 From: Eric Raijmakers Date: Thu, 1 Oct 2020 19:27:28 +0200 Subject: [PATCH 057/105] Fix wrong step size in wxImage::Paste() Fix a bug with wrong size passed to memset() introduced in 1f0ade29f0 (Fix using mask colour even if there is no mask in wxImage::Paste, 2020-09-30) which caused memory corruption and add a test (the one with the large negative vertical offset) allowing to reproduce this reliably. Closes https://github.com/wxWidgets/wxWidgets/pull/2067 --- src/common/image.cpp | 2 +- tests/image/image.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/common/image.cpp b/src/common/image.cpp index 8515cf4c3a..c62d0a909f 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -1764,7 +1764,7 @@ wxImage::Paste(const wxImage & image, int x, int y, // Make all the copied pixels fully opaque if (alpha_target_data != NULL) { - memset(alpha_target_data, wxALPHA_OPAQUE, target_alpha_step); + memset(alpha_target_data, wxALPHA_OPAQUE, width); alpha_target_data += target_alpha_step; } } diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 3672a31ff5..9f72e942b2 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -1839,6 +1839,21 @@ TEST_CASE("wxImage::Paste", "[image][paste]") CHECK_THAT(actual, CenterAlphaPixelEquals(255)); CHECK_THAT(actual, RGBSameAs(black)); } + SECTION("Paste large image with negative vertical offset") + { + wxImage target(442, 249); + wxImage to_be_pasted(345, 24900); + target.InitAlpha(); + target.Paste(to_be_pasted, 48, -12325, wxIMAGE_ALPHA_BLEND_COMPOSE); + } + SECTION("Paste large image with negative horizontal offset") + { + wxImage target(249, 442); + wxImage to_be_pasted(24900, 345); + target.InitAlpha(); + target.Paste(to_be_pasted, -12325, 48, wxIMAGE_ALPHA_BLEND_COMPOSE); + } + } /* From d18e7718fd76e359af9b79ba9fe2fae40fdaaa1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Thu, 1 Oct 2020 23:33:18 +0200 Subject: [PATCH 058/105] Fix wxWindowId parameter type and name in wxHtmlHelpWindow The type obviously should be wxWindowID, not int. Rename the parameter, as it is the only instance where the id is not named 'id', the implementation already uses 'id', and for Phoenix naming it id is also preferred, as the name is used for mangling. The naming change causes no further breakage for Phoenix, as the generator is currently broken anyway for this case. Closes https://github.com/wxWidgets/wxWidgets/pull/2069 --- include/wx/html/helpwnd.h | 2 +- interface/wx/html/helpwnd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/wx/html/helpwnd.h b/include/wx/html/helpwnd.h index 54639ad877..ffa8369c41 100644 --- a/include/wx/html/helpwnd.h +++ b/include/wx/html/helpwnd.h @@ -80,7 +80,7 @@ class WXDLLIMPEXP_HTML wxHtmlHelpWindow : public wxWindow public: wxHtmlHelpWindow(wxHtmlHelpData* data = NULL) { Init(data); } - wxHtmlHelpWindow(wxWindow* parent, wxWindowID wxWindowID, + wxHtmlHelpWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, int style = wxTAB_TRAVERSAL|wxNO_BORDER, diff --git a/interface/wx/html/helpwnd.h b/interface/wx/html/helpwnd.h index e2b17d7fbe..99f67fc0e5 100644 --- a/interface/wx/html/helpwnd.h +++ b/interface/wx/html/helpwnd.h @@ -77,7 +77,7 @@ public: For the values of @a helpStyle, please see the documentation for wxHtmlHelpController. */ - wxHtmlHelpWindow(wxWindow* parent, int wxWindowID, + wxHtmlHelpWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, int style = wxTAB_TRAVERSAL|wxBORDER_NONE, From aef3976e13255d4cbb3952b640e2d13eb752e501 Mon Sep 17 00:00:00 2001 From: Paul Cornett Date: Fri, 2 Oct 2020 11:10:14 -0700 Subject: [PATCH 059/105] Fix WriteText() not scrolling to bottom with GTK >= 3.14 The introduction of scrollbar animations broke scroll-to-end functionality when large amounts of text are written, due to interactions with GtkTextView's background layout. Work around this by scrolling after the layout has finished. See #18864 --- include/wx/gtk/textctrl.h | 4 ++- src/gtk/textctrl.cpp | 60 ++++++++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/include/wx/gtk/textctrl.h b/include/wx/gtk/textctrl.h index 13bf1a36a5..ebc2f02e0a 100644 --- a/include/wx/gtk/textctrl.h +++ b/include/wx/gtk/textctrl.h @@ -143,6 +143,7 @@ public: GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL); void GTKOnTextChanged() wxOVERRIDE; + void GTKAfterLayout(); protected: // overridden wxWindow virtual methods @@ -216,8 +217,9 @@ private: // a dummy one when frozen GtkTextBuffer *m_buffer; - GtkTextMark* m_showPositionOnThaw; + GtkTextMark* m_showPositionDefer; GSList* m_anonymousMarkList; + unsigned m_afterLayoutId; // For wxTE_AUTO_URL void OnUrlMouseEvent(wxMouseEvent&); diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index 4e4cf7a5b5..977954ca35 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -684,8 +684,9 @@ void wxTextCtrl::Init() m_text = NULL; m_buffer = NULL; - m_showPositionOnThaw = NULL; + m_showPositionDefer = NULL; m_anonymousMarkList = NULL; + m_afterLayoutId = 0; } wxTextCtrl::~wxTextCtrl() @@ -702,6 +703,8 @@ wxTextCtrl::~wxTextCtrl() if (m_anonymousMarkList) g_slist_free(m_anonymousMarkList); + if (m_afterLayoutId) + g_source_remove(m_afterLayoutId); } wxTextCtrl::wxTextCtrl( wxWindow *parent, @@ -1102,6 +1105,25 @@ bool wxTextCtrl::IsEmpty() const return wxTextEntry::IsEmpty(); } +void wxTextCtrl::GTKAfterLayout() +{ + m_afterLayoutId = 0; + if (m_showPositionDefer && !IsFrozen()) + { + gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), m_showPositionDefer); + m_showPositionDefer = NULL; + } +} + +extern "C" { +static gboolean afterLayout(void* data) +{ + wxTextCtrl* win = static_cast(data); + win->GTKAfterLayout(); + return false; +} +} + void wxTextCtrl::WriteText( const wxString &text ) { wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") ); @@ -1163,15 +1185,16 @@ void wxTextCtrl::WriteText( const wxString &text ) gtk_text_buffer_delete_selection(m_buffer, false, true); // Insert the text + GtkTextMark* insertMark = gtk_text_buffer_get_insert(m_buffer); GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark( m_buffer, &iter, - gtk_text_buffer_get_insert (m_buffer) ); + gtk_text_buffer_get_iter_at_mark(m_buffer, &iter, insertMark); + + const bool insertIsEnd = gtk_text_iter_is_end(&iter) != 0; gtk_text_buffer_insert( m_buffer, &iter, buffer, buffer.length() ); - // Scroll to cursor, but only if scrollbar thumb is at the very bottom - // won't work when frozen, text view is not using m_buffer then - if (!IsFrozen()) + // Scroll to cursor, if it is at the end and scrollbar thumb is at the bottom + if (insertIsEnd) { GtkAdjustment* adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_widget)); const double value = gtk_adjustment_get_value(adj); @@ -1179,10 +1202,19 @@ void wxTextCtrl::WriteText( const wxString &text ) const double page_size = gtk_adjustment_get_page_size(adj); if (wxIsSameDouble(value, upper - page_size)) { - gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(m_text), - gtk_text_buffer_get_insert(m_buffer), 0, false, 0, 1); + if (!IsFrozen()) + gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), insertMark); + + // GtkTextView's incremental background layout makes scrolling + // to end unreliable until the layout has been completed + m_showPositionDefer = insertMark; } } + if (m_afterLayoutId == 0) + { + m_afterLayoutId = + g_idle_add_full(GTK_TEXT_VIEW_PRIORITY_VALIDATE + 1, afterLayout, this, NULL); + } } wxString wxTextCtrl::GetLineText( long lineNo ) const @@ -1363,7 +1395,7 @@ void wxTextCtrl::SetInsertionPoint( long pos ) GtkTextMark* mark = gtk_text_buffer_get_insert(m_buffer); if (IsFrozen()) // defer until Thaw, text view is not using m_buffer now - m_showPositionOnThaw = mark; + m_showPositionDefer = mark; else gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark); } @@ -1480,7 +1512,7 @@ void wxTextCtrl::ShowPosition( long pos ) gtk_text_buffer_move_mark(m_buffer, mark, &iter); if (IsFrozen()) // defer until Thaw, text view is not using m_buffer now - m_showPositionOnThaw = mark; + m_showPositionDefer = mark; else gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark); } @@ -2136,11 +2168,11 @@ void wxTextCtrl::DoThaw() g_object_unref(m_buffer); g_signal_handler_disconnect(m_buffer, sig_id); - if (m_showPositionOnThaw != NULL) + if (m_showPositionDefer) { - gtk_text_view_scroll_mark_onscreen( - GTK_TEXT_VIEW(m_text), m_showPositionOnThaw); - m_showPositionOnThaw = NULL; + gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), m_showPositionDefer); + if (m_afterLayoutId == 0) + m_showPositionDefer = NULL; } } From 1171155fee9767d24805c9f36501fac937419efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Fri, 2 Oct 2020 20:35:43 +0200 Subject: [PATCH 060/105] Remove LIST_HITTEST_ONITEMRIGHT handling from listtest sample The ONITEMRIGHT case is only meaningful for trees, and according to the code comment, "not used". Closes https://github.com/wxWidgets/wxWidgets/pull/2070 --- samples/listctrl/listtest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/listctrl/listtest.cpp b/samples/listctrl/listtest.cpp index 1c4213098b..2218622b4e 100644 --- a/samples/listctrl/listtest.cpp +++ b/samples/listctrl/listtest.cpp @@ -1442,7 +1442,6 @@ void MyListCtrl::OnRightClick(wxMouseEvent& event) case wxLIST_HITTEST_NOWHERE: where = "nowhere near"; break; case wxLIST_HITTEST_ONITEMICON: where = "on icon of"; break; case wxLIST_HITTEST_ONITEMLABEL: where = "on label of"; break; - case wxLIST_HITTEST_ONITEMRIGHT: where = "right on"; break; case wxLIST_HITTEST_TOLEFT: where = "to the left of"; break; case wxLIST_HITTEST_TORIGHT: where = "to the right of"; break; default: where = "not clear exactly where on"; break; From d47b857b09d5c9ea4be669ffac506664d7d41de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sat, 3 Oct 2020 16:12:04 +0200 Subject: [PATCH 061/105] Change data and shortHelpString to adhere to naming convention Rename data to clientData in the inlined overloads. This change is transparent for any users. Rename shortHelpString to shortHelp (dito for longHelp). Although this change is in general visible for any users, Phoenix already mangles the the parameter names to strip the 'String' suffix. --- include/wx/tbarbase.h | 12 ++++++------ interface/wx/toolbar.h | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/wx/tbarbase.h b/include/wx/tbarbase.h index 6d1b423015..a4b380d6ee 100644 --- a/include/wx/tbarbase.h +++ b/include/wx/tbarbase.h @@ -295,10 +295,10 @@ public: wxItemKind kind = wxITEM_NORMAL, const wxString& shortHelp = wxEmptyString, const wxString& longHelp = wxEmptyString, - wxObject *data = NULL) + wxObject *clientData = NULL) { return DoAddTool(toolid, label, bitmap, bmpDisabled, kind, - shortHelp, longHelp, data); + shortHelp, longHelp, clientData); } // the most common AddTool() version @@ -318,10 +318,10 @@ public: const wxBitmap& bmpDisabled = wxNullBitmap, const wxString& shortHelp = wxEmptyString, const wxString& longHelp = wxEmptyString, - wxObject *data = NULL) + wxObject *clientData = NULL) { return AddTool(toolid, label, bitmap, bmpDisabled, wxITEM_CHECK, - shortHelp, longHelp, data); + shortHelp, longHelp, clientData); } // add a radio tool, i.e. a tool which can be toggled and releases any @@ -332,10 +332,10 @@ public: const wxBitmap& bmpDisabled = wxNullBitmap, const wxString& shortHelp = wxEmptyString, const wxString& longHelp = wxEmptyString, - wxObject *data = NULL) + wxObject *clientData = NULL) { return AddTool(toolid, label, bitmap, bmpDisabled, wxITEM_RADIO, - shortHelp, longHelp, data); + shortHelp, longHelp, clientData); } diff --git a/interface/wx/toolbar.h b/interface/wx/toolbar.h index 84506d9589..3cdb064c73 100644 --- a/interface/wx/toolbar.h +++ b/interface/wx/toolbar.h @@ -462,9 +462,9 @@ public: whenever another button in the group is checked. ::wxITEM_DROPDOWN specifies that a drop-down menu button will appear next to the tool button (only GTK+ and MSW). Call SetDropdownMenu() afterwards. - @param shortHelpString + @param shortHelp This string is used for the tools tooltip. - @param longHelpString + @param longHelp This string is shown in the statusbar (if any) of the parent frame when the mouse pointer is inside the tool. @param clientData @@ -481,8 +481,8 @@ public: const wxBitmap& bitmap, const wxBitmap& bmpDisabled, wxItemKind kind = wxITEM_NORMAL, - const wxString& shortHelpString = wxEmptyString, - const wxString& longHelpString = wxEmptyString, + const wxString& shortHelp = wxEmptyString, + const wxString& longHelp = wxEmptyString, wxObject* clientData = NULL); //@} From 03e6ca87dba8a5e1d7e777f4fbdba4f1fbd24c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sat, 3 Oct 2020 16:19:06 +0200 Subject: [PATCH 062/105] Revert client_data parameter name to clientData Commit 5925893eed47 ("Fix various doxygen issues in the documentation") changed the name to client_data. This does not fit the naming scheme, and breaks some code in Phoenix which assumes the param is called clientData (to be able to use a binding specific type for it). --- interface/wx/ribbon/toolbar.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/wx/ribbon/toolbar.h b/interface/wx/ribbon/toolbar.h index cb6045d665..77fff36f0e 100644 --- a/interface/wx/ribbon/toolbar.h +++ b/interface/wx/ribbon/toolbar.h @@ -130,7 +130,7 @@ public: The UI help string to associate with the new tool. @param kind The kind of tool to add. - @param client_data + @param clientData Client data to associate with the new tool. @return An opaque pointer which can be used only with other tool bar @@ -144,7 +144,7 @@ public: const wxBitmap& bitmap_disabled = wxNullBitmap, const wxString& help_string = wxEmptyString, wxRibbonButtonKind kind = wxRIBBON_BUTTON_NORMAL, - wxObject* client_data = NULL); + wxObject* clientData = NULL); /** Add a separator to the tool bar. @@ -232,7 +232,7 @@ public: The UI help string to associate with the new tool. @param kind The kind of tool to add. - @param client_data + @param clientData Client data to associate with the new tool. @return An opaque pointer which can be used only with other tool bar @@ -249,7 +249,7 @@ public: const wxBitmap& bitmap_disabled = wxNullBitmap, const wxString& help_string = wxEmptyString, wxRibbonButtonKind kind = wxRIBBON_BUTTON_NORMAL, - wxObject* client_data = NULL); + wxObject* clientData = NULL); /** Insert a separator to the tool bar at the specified position. From 2b8fd103b709f8026cc95e01b47f7f21513e3c42 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Wed, 13 Feb 2019 15:00:23 +0200 Subject: [PATCH 063/105] Add wxConvAuto::IsFallbackEncoding() --- include/wx/convauto.h | 6 ++++++ interface/wx/convauto.h | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/include/wx/convauto.h b/include/wx/convauto.h index 3da6c6adc4..caab99973f 100644 --- a/include/wx/convauto.h +++ b/include/wx/convauto.h @@ -91,6 +91,12 @@ public: return m_bomType; } + // Return true if the fall-back encoding is used + bool IsFallbackEncoding() const + { + return m_ownsConv && m_bomType == wxBOM_None; + } + private: // common part of all ctors void Init() diff --git a/interface/wx/convauto.h b/interface/wx/convauto.h index 7ddfb26927..90e769c32a 100644 --- a/interface/wx/convauto.h +++ b/interface/wx/convauto.h @@ -146,6 +146,13 @@ public: */ wxBOM GetBOM() const; + /** + Check if the fall-back encoding is used. + + @since 3.1.5 + */ + bool IsFallbackEncoding() const; + /** Return a pointer to the characters that makes up this BOM. From 307a97dadfe7a796aa6025ce2da2f6f8196db133 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Sun, 20 Sep 2020 21:40:19 +0300 Subject: [PATCH 064/105] Add wxConvAuto::IsUTF8() --- include/wx/convauto.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/wx/convauto.h b/include/wx/convauto.h index caab99973f..23b21dc41c 100644 --- a/include/wx/convauto.h +++ b/include/wx/convauto.h @@ -78,6 +78,8 @@ public: virtual size_t GetMBNulLen() const wxOVERRIDE { return m_conv->GetMBNulLen(); } + virtual bool IsUTF8() const wxOVERRIDE { return m_conv && m_conv->IsUTF8(); } + virtual wxMBConv *Clone() const wxOVERRIDE { return new wxConvAuto(*this); } // return the BOM type of this buffer From 28823424e9c3d0a56aff76057c00b023ea04500a Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Tue, 22 Sep 2020 17:42:07 +0300 Subject: [PATCH 065/105] Add wxConvAuto::GetEncoding() --- include/wx/convauto.h | 2 ++ interface/wx/convauto.h | 9 +++++++++ src/common/convauto.cpp | 31 +++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/include/wx/convauto.h b/include/wx/convauto.h index 23b21dc41c..57212ab1ad 100644 --- a/include/wx/convauto.h +++ b/include/wx/convauto.h @@ -93,6 +93,8 @@ public: return m_bomType; } + wxFontEncoding GetEncoding() const; + // Return true if the fall-back encoding is used bool IsFallbackEncoding() const { diff --git a/interface/wx/convauto.h b/interface/wx/convauto.h index 90e769c32a..788d6ec2b9 100644 --- a/interface/wx/convauto.h +++ b/interface/wx/convauto.h @@ -146,6 +146,15 @@ public: */ wxBOM GetBOM() const; + /** + Return the detected encoding + + Returns @c wxFONTENCODING_MAX if called before the first use. + + @since 3.1.5 + */ + wxBOM GetEncoding() const; + /** Check if the fall-back encoding is used. diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp index 952b4455f5..dca91eb59b 100644 --- a/src/common/convauto.cpp +++ b/src/common/convauto.cpp @@ -351,3 +351,34 @@ wxConvAuto::FromWChar(char *dst, size_t dstLen, return m_conv->FromWChar(dst, dstLen, src, srcLen); } + +wxFontEncoding wxConvAuto::GetEncoding() const +{ + switch ( m_bomType ) + { + case wxBOM_UTF32BE: + return wxFONTENCODING_UTF32BE; + case wxBOM_UTF32LE: + return wxFONTENCODING_UTF32LE; + case wxBOM_UTF16BE: + return wxFONTENCODING_UTF16BE; + case wxBOM_UTF16LE: + return wxFONTENCODING_UTF16LE; + case wxBOM_UTF8: + return wxFONTENCODING_UTF8; + + case wxBOM_Unknown: + case wxBOM_None: + if ( !m_conv ) + return wxFONTENCODING_MAX; + else if ( !m_ownsConv ) + return wxFONTENCODING_UTF8; + else if ( m_encDefault != wxFONTENCODING_DEFAULT ) + return m_encDefault; + else + return GetFallbackEncoding(); + } + + wxFAIL_MSG( "unknown BOM type" ); + return wxFONTENCODING_MAX; +} From 3676635231ec3dde41c86049e43e1f18a8a725b3 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Wed, 23 Sep 2020 14:43:01 +0300 Subject: [PATCH 066/105] Check wxConvAuto state in tests --- tests/mbconv/convautotest.cpp | 43 +++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/tests/mbconv/convautotest.cpp b/tests/mbconv/convautotest.cpp index 6a5d5791d1..cde714b109 100644 --- a/tests/mbconv/convautotest.cpp +++ b/tests/mbconv/convautotest.cpp @@ -50,12 +50,33 @@ private: CPPUNIT_TEST( StreamUTF32BE ); CPPUNIT_TEST_SUITE_END(); + // expected converter state, UTF-8 without BOM by default + struct ConvState + { + ConvState( wxBOM bom = wxBOM_None, + wxFontEncoding enc = wxFONTENCODING_UTF8, + bool fallback = false ) + : m_bom(bom), m_enc(enc), m_fallback(fallback) {} + + void Check(const wxConvAuto& conv) const + { + CPPUNIT_ASSERT( conv.GetBOM() == m_bom ); + CPPUNIT_ASSERT( conv.GetEncoding() == m_enc ); + CPPUNIT_ASSERT( conv.IsFallbackEncoding() == m_fallback ); + CPPUNIT_ASSERT( conv.IsUTF8() == (m_enc == wxFONTENCODING_UTF8) ); + } + + wxBOM m_bom; + wxFontEncoding m_enc; + bool m_fallback; + }; + // real test function: check that converting the src multibyte string to // wide char using wxConvAuto yields wch as the first result // // the length of the string may need to be passed explicitly if it has // embedded NULs, otherwise it's not necessary - void TestFirstChar(const char *src, wchar_t wch, size_t len = wxNO_LEN); + void TestFirstChar(const char *src, wchar_t wch, size_t len = wxNO_LEN, ConvState st = ConvState()); void Empty(); void Short(); @@ -90,16 +111,20 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ConvAutoTestCase, "ConvAutoTestCase"); // tests // ---------------------------------------------------------------------------- -void ConvAutoTestCase::TestFirstChar(const char *src, wchar_t wch, size_t len) +void ConvAutoTestCase::TestFirstChar(const char *src, wchar_t wch, size_t len, ConvState st) { - wxWCharBuffer wbuf = wxConvAuto().cMB2WC(src, len, NULL); + wxConvAuto conv; + wxWCharBuffer wbuf = conv.cMB2WC(src, len, NULL); CPPUNIT_ASSERT( wbuf ); CPPUNIT_ASSERT_EQUAL( wch, *wbuf ); + st.Check(conv); } void ConvAutoTestCase::Empty() { - CPPUNIT_ASSERT( !wxConvAuto().cMB2WC("") ); + wxConvAuto conv; + CPPUNIT_ASSERT( !conv.cMB2WC("") ); + ConvState(wxBOM_Unknown, wxFONTENCODING_MAX).Check(conv); } void ConvAutoTestCase::Short() @@ -114,28 +139,28 @@ void ConvAutoTestCase::None() void ConvAutoTestCase::UTF32LE() { - TestFirstChar("\xff\xfe\0\0A\0\0\0", wxT('A'), 8); + TestFirstChar("\xff\xfe\0\0A\0\0\0", wxT('A'), 8, ConvState(wxBOM_UTF32LE, wxFONTENCODING_UTF32LE)); } void ConvAutoTestCase::UTF32BE() { - TestFirstChar("\0\0\xfe\xff\0\0\0B", wxT('B'), 8); + TestFirstChar("\0\0\xfe\xff\0\0\0B", wxT('B'), 8, ConvState(wxBOM_UTF32BE, wxFONTENCODING_UTF32BE)); } void ConvAutoTestCase::UTF16LE() { - TestFirstChar("\xff\xfeZ\0", wxT('Z'), 4); + TestFirstChar("\xff\xfeZ\0", wxT('Z'), 4, ConvState(wxBOM_UTF16LE, wxFONTENCODING_UTF16LE)); } void ConvAutoTestCase::UTF16BE() { - TestFirstChar("\xfe\xff\0Y", wxT('Y'), 4); + TestFirstChar("\xfe\xff\0Y", wxT('Y'), 4, ConvState(wxBOM_UTF16BE, wxFONTENCODING_UTF16BE)); } void ConvAutoTestCase::UTF8() { #ifdef wxHAVE_U_ESCAPE - TestFirstChar("\xef\xbb\xbf\xd0\x9f", L'\u041f'); + TestFirstChar("\xef\xbb\xbf\xd0\x9f", L'\u041f', wxNO_LEN, ConvState(wxBOM_UTF8, wxFONTENCODING_UTF8)); #endif } From 857950c62665948033c873d4e59731f07cc99370 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Mon, 28 Sep 2020 21:02:46 +0300 Subject: [PATCH 067/105] Add more wxConvAuto test cases --- tests/mbconv/convautotest.cpp | 93 +++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 14 deletions(-) diff --git a/tests/mbconv/convautotest.cpp b/tests/mbconv/convautotest.cpp index cde714b109..91b940a35b 100644 --- a/tests/mbconv/convautotest.cpp +++ b/tests/mbconv/convautotest.cpp @@ -34,7 +34,9 @@ public: private: CPPUNIT_TEST_SUITE( ConvAutoTestCase ); + CPPUNIT_TEST( Init ); CPPUNIT_TEST( Empty ); + CPPUNIT_TEST( Encode ); CPPUNIT_TEST( Short ); CPPUNIT_TEST( None ); CPPUNIT_TEST( UTF32LE ); @@ -42,12 +44,17 @@ private: CPPUNIT_TEST( UTF16LE ); CPPUNIT_TEST( UTF16BE ); CPPUNIT_TEST( UTF8 ); + CPPUNIT_TEST( UTF8NoBom ); + CPPUNIT_TEST( Fallback ); + CPPUNIT_TEST( FallbackMultibyte ); CPPUNIT_TEST( StreamUTF8NoBOM ); CPPUNIT_TEST( StreamUTF8 ); CPPUNIT_TEST( StreamUTF16LE ); CPPUNIT_TEST( StreamUTF16BE ); CPPUNIT_TEST( StreamUTF32LE ); CPPUNIT_TEST( StreamUTF32BE ); + CPPUNIT_TEST( StreamFallback ); + CPPUNIT_TEST( StreamFallbackMultibyte ); CPPUNIT_TEST_SUITE_END(); // expected converter state, UTF-8 without BOM by default @@ -76,9 +83,13 @@ private: // // the length of the string may need to be passed explicitly if it has // embedded NULs, otherwise it's not necessary - void TestFirstChar(const char *src, wchar_t wch, size_t len = wxNO_LEN, ConvState st = ConvState()); + void TestFirstChar(const char *src, wchar_t wch, size_t len = wxNO_LEN, + ConvState st = ConvState(), + wxFontEncoding fe = wxFONTENCODING_DEFAULT); + void Init(); void Empty(); + void Encode(); void Short(); void None(); void UTF32LE(); @@ -86,12 +97,16 @@ private: void UTF16LE(); void UTF16BE(); void UTF8(); + void UTF8NoBom(); + void Fallback(); + void FallbackMultibyte(); // test whether two lines of text are converted properly from a stream void TestTextStream(const char *src, size_t srclength, const wxString& line1, - const wxString& line2); + const wxString& line2, + wxFontEncoding fe = wxFONTENCODING_DEFAULT); void StreamUTF8NoBOM(); void StreamUTF8(); @@ -99,6 +114,8 @@ private: void StreamUTF16BE(); void StreamUTF32LE(); void StreamUTF32BE(); + void StreamFallback(); + void StreamFallbackMultibyte(); }; // register in the unnamed registry so that these tests are run by default @@ -111,15 +128,21 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ConvAutoTestCase, "ConvAutoTestCase"); // tests // ---------------------------------------------------------------------------- -void ConvAutoTestCase::TestFirstChar(const char *src, wchar_t wch, size_t len, ConvState st) +void ConvAutoTestCase::TestFirstChar(const char *src, wchar_t wch, size_t len, + ConvState st, wxFontEncoding fe) { - wxConvAuto conv; + wxConvAuto conv(fe); wxWCharBuffer wbuf = conv.cMB2WC(src, len, NULL); CPPUNIT_ASSERT( wbuf ); CPPUNIT_ASSERT_EQUAL( wch, *wbuf ); st.Check(conv); } +void ConvAutoTestCase::Init() +{ + ConvState(wxBOM_Unknown, wxFONTENCODING_MAX).Check(wxConvAuto()); +} + void ConvAutoTestCase::Empty() { wxConvAuto conv; @@ -127,6 +150,16 @@ void ConvAutoTestCase::Empty() ConvState(wxBOM_Unknown, wxFONTENCODING_MAX).Check(conv); } +void ConvAutoTestCase::Encode() +{ + wxConvAuto conv; + wxString str = wxString::FromUTF8("\xd0\x9f\xe3\x81\x82"); + wxCharBuffer buf = conv.cWC2MB(str.wc_str()); + CPPUNIT_ASSERT( buf ); + CPPUNIT_ASSERT_EQUAL( str, wxString::FromUTF8(buf) ); + ConvState(wxBOM_Unknown, wxFONTENCODING_UTF8).Check(conv); +} + void ConvAutoTestCase::Short() { TestFirstChar("1", wxT('1')); @@ -164,13 +197,39 @@ void ConvAutoTestCase::UTF8() #endif } +void ConvAutoTestCase::UTF8NoBom() +{ +#ifdef wxHAVE_U_ESCAPE + TestFirstChar("\xd0\x9f\xe3\x81\x82", L'\u041f', wxNO_LEN, ConvState(wxBOM_None, wxFONTENCODING_UTF8)); +#endif +} + +void ConvAutoTestCase::Fallback() +{ +#ifdef wxHAVE_U_ESCAPE + TestFirstChar("\xbf", L'\u041f', wxNO_LEN, + ConvState(wxBOM_None, wxFONTENCODING_ISO8859_5, true), + wxFONTENCODING_ISO8859_5); +#endif +} + +void ConvAutoTestCase::FallbackMultibyte() +{ +#ifdef wxHAVE_U_ESCAPE + TestFirstChar("\x84\x50", L'\u041f', wxNO_LEN, + ConvState(wxBOM_None, wxFONTENCODING_CP932, true), + wxFONTENCODING_CP932); +#endif +} + void ConvAutoTestCase::TestTextStream(const char *src, size_t srclength, const wxString& line1, - const wxString& line2) + const wxString& line2, + wxFontEncoding fe) { wxMemoryInputStream instream(src, srclength); - wxTextInputStream text(instream); + wxTextInputStream text(instream, wxT(" \t"), wxConvAuto(fe)); CPPUNIT_ASSERT_EQUAL( line1, text.ReadLine() ); CPPUNIT_ASSERT_EQUAL( line2, text.ReadLine() ); @@ -191,16 +250,8 @@ const wxString line2 = wxString::FromUTF8("\xce\xb2"); void ConvAutoTestCase::StreamUTF8NoBOM() { - // currently this test doesn't work because without the BOM wxConvAuto - // decides that the string is in Latin-1 after finding the first (but not - // the two subsequent ones which are part of the same UTF-8 sequence!) - // 8-bit character - // - // FIXME: we need to fix this at wxTextInputStream level, see #11570 -#if 0 TestTextStream("\x61\xE3\x81\x82\x0A\xCE\xB2", 7, line1, line2); -#endif } void ConvAutoTestCase::StreamUTF8() @@ -235,4 +286,18 @@ void ConvAutoTestCase::StreamUTF32BE() 20, line1, line2); } +void ConvAutoTestCase::StreamFallback() +{ + // this only works if there are at least 3 bytes after the first non-ASCII character + TestTextStream("\x61\xbf\x0A\xe0\x7a", + 5, wxString::FromUTF8("a\xd0\x9f"), wxString::FromUTF8("\xd1\x80z"), + wxFONTENCODING_ISO8859_5); +} + +void ConvAutoTestCase::StreamFallbackMultibyte() +{ + TestTextStream("\x61\x82\xa0\x0A\x83\xc0", + 6, line1, line2, wxFONTENCODING_CP932); +} + #endif // wxUSE_UNICODE From 1e435d2347cf76337386da9fad43406e49f2ea2f Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Mon, 28 Sep 2020 21:58:52 +0300 Subject: [PATCH 068/105] Fix wxTextInputStream incorrectly decoding multibyte fallback encodings --- src/common/txtstrm.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/common/txtstrm.cpp b/src/common/txtstrm.cpp index c38f7c29ab..fc5e352b58 100644 --- a/src/common/txtstrm.cpp +++ b/src/common/txtstrm.cpp @@ -134,12 +134,13 @@ wxChar wxTextInputStream::GetChar() // one extra byte, the only explanation is that we were using a // wxConvAuto conversion recognizing the initial BOM and that // it couldn't detect the presence or absence of BOM so far, - // but now finally has enough data to see that there is none. - // As we must have fallen back to Latin-1 in this case, return - // just the first byte and keep the other ones for the next - // time. - m_validBegin = 1; - return wbuf[0]; + // but now finally has enough data to see that there is none, or + // it was trying to decode the data as UTF-8 sequence, but now + // recognized that it's not valid UTF-8 and switched to fallback. + // We don't know how long is the first character or if it's decoded + // as 1 or 2 wchar_t characters, so we need to start with 1 byte again. + inlen = -1; + break; #if SIZEOF_WCHAR_T == 2 case 2: From bc838b4773ab3a93be5ff869a9357b72b9cf875a Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Mon, 28 Sep 2020 22:11:17 +0300 Subject: [PATCH 069/105] Do not delete and create the fallback conversion again when it fails --- src/common/convauto.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp index dca91eb59b..50c5a956c7 100644 --- a/src/common/convauto.cpp +++ b/src/common/convauto.cpp @@ -307,7 +307,7 @@ wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, // try to convert using the auto-detected encoding size_t rc = m_conv->ToWChar(dst, dstLen, src, srcLen); - if ( rc == wxCONV_FAILED && m_bomType == wxBOM_None ) + if ( rc == wxCONV_FAILED && m_bomType == wxBOM_None && !m_ownsConv ) { // we may need more bytes before we can decode the input, don't switch // to the fall-back conversion in this case as it would prevent us from @@ -320,9 +320,6 @@ wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, // simply tried UTF-8 by default, retry it using the fall-back if ( m_encDefault != wxFONTENCODING_MAX ) { - if ( m_ownsConv ) - delete m_conv; - self->m_conv = new wxCSConv(m_encDefault == wxFONTENCODING_DEFAULT ? GetFallbackEncoding() : m_encDefault); From b3eff48e28f4d1f7a7ea56f10522473cb150aff9 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Tue, 29 Sep 2020 15:35:53 +0300 Subject: [PATCH 070/105] Switch to fallback earlier if the input is not valid UTF-8 prefix --- include/wx/strconv.h | 2 ++ src/common/convauto.cpp | 2 +- src/common/strconv.cpp | 20 ++++++++++++++++++++ tests/mbconv/convautotest.cpp | 5 ++--- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/wx/strconv.h b/include/wx/strconv.h index c1b070d36a..21c5f136b1 100644 --- a/include/wx/strconv.h +++ b/include/wx/strconv.h @@ -387,6 +387,8 @@ private: int m_options; }; +bool wxIsUTF8Prefix(const char *src, size_t len); + // ---------------------------------------------------------------------------- // wxMBConvUTF16Base: for both LE and BE variants // ---------------------------------------------------------------------------- diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp index 50c5a956c7..7b92d396f6 100644 --- a/src/common/convauto.cpp +++ b/src/common/convauto.cpp @@ -313,7 +313,7 @@ wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, // to the fall-back conversion in this case as it would prevent us from // decoding UTF-8 input when fed it byte by byte, as done by // wxTextInputStream, for example - if ( srcLen < m_conv->GetMaxCharLen() ) + if ( srcLen < m_conv->GetMaxCharLen() && wxIsUTF8Prefix(src, srcLen) ) return wxCONV_FAILED; // if the conversion failed but we didn't really detect anything and diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index ba25dae157..04f6e451ec 100644 --- a/src/common/strconv.cpp +++ b/src/common/strconv.cpp @@ -1446,6 +1446,26 @@ size_t wxMBConvUTF8::FromWChar(char *buf, size_t n, return len; } +// checks if the input can be the beginning of a valid UTF-8 string +bool wxIsUTF8Prefix(const char *src, size_t len) +{ + unsigned char l; + for ( size_t i = 0; i < len; ++i ) + { + l = tableUtf8Lengths[(unsigned char)src[i]]; + if ( !l ) + return false; // invalid leading byte + while ( --l ) + { + if ( ++i == len ) + return true; // truncated sequence + if ( (src[i] & 0xC0) != 0x80 ) + return false; // invalid continuation byte + } + } + return true; +} + // ============================================================================ // UTF-16 // ============================================================================ diff --git a/tests/mbconv/convautotest.cpp b/tests/mbconv/convautotest.cpp index 91b940a35b..789e7582aa 100644 --- a/tests/mbconv/convautotest.cpp +++ b/tests/mbconv/convautotest.cpp @@ -288,9 +288,8 @@ void ConvAutoTestCase::StreamUTF32BE() void ConvAutoTestCase::StreamFallback() { - // this only works if there are at least 3 bytes after the first non-ASCII character - TestTextStream("\x61\xbf\x0A\xe0\x7a", - 5, wxString::FromUTF8("a\xd0\x9f"), wxString::FromUTF8("\xd1\x80z"), + TestTextStream("\x61\xbf\x0A\xe0", + 4, wxString::FromUTF8("a\xd0\x9f"), wxString::FromUTF8("\xd1\x80"), wxFONTENCODING_ISO8859_5); } From 45adce85618f05cdffc08ef2df76547701cc17b2 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Sat, 3 Oct 2020 18:21:18 +0300 Subject: [PATCH 071/105] Fix wxTextInputStream for some inputs starting with nulls --- src/common/convauto.cpp | 2 +- src/common/txtstrm.cpp | 9 +++---- tests/streams/textstreamtest.cpp | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp index 7b92d396f6..d5d6079b32 100644 --- a/src/common/convauto.cpp +++ b/src/common/convauto.cpp @@ -313,7 +313,7 @@ wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, // to the fall-back conversion in this case as it would prevent us from // decoding UTF-8 input when fed it byte by byte, as done by // wxTextInputStream, for example - if ( srcLen < m_conv->GetMaxCharLen() && wxIsUTF8Prefix(src, srcLen) ) + if ( srcLen < 2 + m_conv->GetMaxCharLen() && wxIsUTF8Prefix(src, srcLen) ) return wxCONV_FAILED; // if the conversion failed but we didn't really detect anything and diff --git a/src/common/txtstrm.cpp b/src/common/txtstrm.cpp index fc5e352b58..1332bb3cf0 100644 --- a/src/common/txtstrm.cpp +++ b/src/common/txtstrm.cpp @@ -97,10 +97,11 @@ wxChar wxTextInputStream::GetChar() m_validEnd = 0; } - // We may need to decode up to 4 characters if we have input starting with - // 3 BOM-like bytes, but not actually containing a BOM, as decoding it will - // only succeed when 4 bytes are read -- and will yield 4 wide characters. - wxChar wbuf[4]; + // We may need to decode up to 6 characters if we have input starting with + // 2 null bytes (like in UTF-32BE BOM), and then 3 bytes that look like + // the start of UTF-8 sequence, as decoding it will only succeed when + // 6 bytes are read -- and will yield 6 wide characters. + wxChar wbuf[6]; for(size_t inlen = 0; inlen < sizeof(m_lastBytes); inlen++) { if ( inlen >= m_validEnd ) diff --git a/tests/streams/textstreamtest.cpp b/tests/streams/textstreamtest.cpp index edb6eaa8a2..c6497b23f2 100644 --- a/tests/streams/textstreamtest.cpp +++ b/tests/streams/textstreamtest.cpp @@ -324,6 +324,46 @@ TEST_CASE("wxTextInputStream::GetChar", "[text][input][stream][char]") REQUIRE( tis.GetChar() == 0x00 ); CHECK( tis.GetInputStream().Eof() ); } + + // Two null bytes that look like the start of UTF-32BE BOM, + // followed by 4 byte UTF-8 sequence. + // Needs wxConvAuto to not switch to fallback on <6 bytes. + SECTION("UTF8-with-nulls") + { + const wxUint8 buf[] = { 0x00, 0x00, 0xf0, 0x90, 0x8c, 0x98 }; + wxMemoryInputStream mis(buf, sizeof(buf)); + wxTextInputStream tis(mis); + + wxCharTypeBuffer e = wxString::FromUTF8((char*)buf, sizeof(buf)) + .tchar_str(); + for ( size_t i = 0; i < e.length(); ++i ) + { + INFO("i = " << i); + REQUIRE( tis.GetChar() == e[i] ); + } + REQUIRE( tis.GetChar() == 0x00 ); + CHECK( tis.GetInputStream().Eof() ); + } + + // Two null bytes that look like the start of UTF-32BE BOM, + // then 3 bytes that look like the start of UTF-8 sequence. + // Needs 6 character output buffer in GetChar(). + SECTION("almost-UTF8-with-nulls") + { + const wxUint8 buf[] = { 0x00, 0x00, 0xf0, 0x90, 0x8c, 0xe0 }; + wxMemoryInputStream mis(buf, sizeof(buf)); + wxTextInputStream tis(mis); + + wxCharTypeBuffer e = wxString((char*)buf, wxCSConv(wxFONTENCODING_ISO8859_1), + sizeof(buf)).tchar_str(); + for ( size_t i = 0; i < e.length(); ++i ) + { + INFO("i = " << i); + REQUIRE( tis.GetChar() == e[i] ); + } + REQUIRE( tis.GetChar() == 0x00 ); + CHECK( tis.GetInputStream().Eof() ); + } } #endif // wxUSE_UNICODE From 4f90d31274ef6a5ac70762ed9567c75bc63b9d3b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Oct 2020 16:00:34 +0200 Subject: [PATCH 072/105] Harmonize wxXmlDoctype ctor parameter names Make the names more clear and similar to the names of member variables to which they correspond and also use them consistently in the documentation. This reverts the changes to this interface header done in 5925893eed (Fix various doxygen issues in the documentation, 2019-10-20). --- include/wx/xml/xml.h | 10 ++++++---- interface/wx/xml/xml.h | 12 ++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/wx/xml/xml.h b/include/wx/xml/xml.h index a596ae92e4..a816ce22ff 100644 --- a/include/wx/xml/xml.h +++ b/include/wx/xml/xml.h @@ -241,10 +241,12 @@ class WXDLLIMPEXP_XML wxXmlDoctype { public: explicit - wxXmlDoctype(const wxString& name = wxString(), - const wxString& sysid = wxString(), - const wxString& pubid = wxString()) - : m_rootName(name), m_systemId(sysid), m_publicId(pubid) + wxXmlDoctype(const wxString& rootName = wxString(), + const wxString& systemId = wxString(), + const wxString& publicId = wxString()) + : m_rootName(rootName), + m_systemId(systemId), + m_publicId(publicId) {} // Default copy ctor and assignment operators are ok. diff --git a/interface/wx/xml/xml.h b/interface/wx/xml/xml.h index 0eaad72423..4c58080b75 100644 --- a/interface/wx/xml/xml.h +++ b/interface/wx/xml/xml.h @@ -494,16 +494,16 @@ public: /** Creates and possible initializes the DOCTYPE. - @param name + @param rootName The root name. - @param sysid + @param systemId The system identifier. - @param pubid + @param publicId The public identifier. */ - wxXmlDoctype(const wxString& name = wxString(), - const wxString& sysid = wxString(), - const wxString& pubid = wxString()); + wxXmlDoctype(const wxString& rootName = wxString(), + const wxString& systemId = wxString(), + const wxString& publicId = wxString()); /** Removes all the DOCTYPE values. From c91ced241295bd90627d88bcde5667fec62dbb36 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Oct 2020 18:19:12 +0200 Subject: [PATCH 073/105] Revert "Fix wxMSW ListCtrl drawing of horizontal rules for new items" This reverts commit 374db28747 (Fix wxMSW ListCtrl drawing of horizontal rules for new items, 2016-05-04) and also commit bb3177dd3b (Avoid infinite repaint loop in wxListCtrl with wxLC_HRULES, 2020-07-24) which fixed one problem with the original change, but not all of them, as it was still easily possible to get into an infinite repaint loop. So just return to the simplest and not too bad, even if not optimal, solution of refreshing everything after changing a column width when using horizontal rules. See #17158, #18850. Closes #18927. --- src/msw/listctrl.cpp | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index b5d912a764..33031f3d70 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -788,7 +788,15 @@ bool wxListCtrl::SetColumnWidth(int col, int width) else if ( width == wxLIST_AUTOSIZE_USEHEADER) width = LVSCW_AUTOSIZE_USEHEADER; - return ListView_SetColumnWidth(GetHwnd(), col, width) != 0; + if ( !ListView_SetColumnWidth(GetHwnd(), col, width) ) + return false; + + // Failure to explicitly refresh the control with horizontal rules results + // in corrupted rules display. + if ( HasFlag(wxLC_HRULES) ) + Refresh(); + + return true; } // ---------------------------------------------------------------------------- @@ -3261,12 +3269,7 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) dc.SetPen(pen); dc.SetBrush(* wxTRANSPARENT_BRUSH); - // Find the coordinate of the right most visible point: this is not the - // same as GetClientSize().x because the window might not be fully visible, - // it could be clipped by its parent. - const int availableWidth = GetParent()->GetClientSize().x - GetPosition().x; - int visibleWidth = wxMin(GetClientSize().x, - availableWidth - GetWindowBorderSize().x); + wxSize clientSize = GetClientSize(); const int countPerPage = GetCountPerPage(); if (countPerPage < 0) @@ -3278,9 +3281,6 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) const long top = GetTopItem(); const long bottom = wxMin(top + countPerPage, itemCount - 1); - wxRect clipRect; - dc.GetClippingBox(clipRect); - if (drawHRules) { wxRect itemRect; @@ -3289,23 +3289,9 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) if (GetItemRect(i, itemRect)) { const int cy = itemRect.GetBottom(); - dc.DrawLine(clipRect.x, cy, clipRect.GetRight() + 1, cy); + dc.DrawLine(0, cy, clientSize.x, cy); } } - - /* - The drawing can be clipped horizontally to the rightmost column. - This happens when an item is added (and visible) and results in a - horizontal rule being clipped instead of drawn across the entire - list control. In that case we request for the part to the right of - the rightmost column to be drawn as well. - */ - if ( clipRect.GetRight() < visibleWidth - 1 && clipRect.width ) - { - RefreshRect(wxRect(clipRect.GetRight(), clipRect.y, - visibleWidth - clipRect.width, clipRect.height), - false /* don't erase background */); - } } if (drawVRules) @@ -3347,7 +3333,7 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) wxDCBrushChanger changeBrush(dc, GetBackgroundColour()); dc.DrawRectangle(0, topItemRect.GetY() - gap, - visibleWidth, gap); + clientSize.GetWidth(), gap); } const int numCols = GetColumnCount(); From 9e5f333bcc399ab4a3aee6258fd062f9c182ca7d Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 4 Oct 2020 21:43:56 +0200 Subject: [PATCH 074/105] Optimize calculations of the angles in DrawArc() Perform calculations in radians to avoid conversions to/from degrees. --- src/common/dcgraph.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp index ff53f27331..2e3afe25fe 100644 --- a/src/common/dcgraph.cpp +++ b/src/common/dcgraph.cpp @@ -27,12 +27,6 @@ #include "wx/geometry.h" #endif -//----------------------------------------------------------------------------- -// constants -//----------------------------------------------------------------------------- - -static const double RAD2DEG = 180.0 / M_PI; - //----------------------------------------------------------------------------- // Local functions //----------------------------------------------------------------------------- @@ -686,11 +680,11 @@ void wxGCDCImpl::DoDrawArc( wxCoord x1, wxCoord y1, double dy = y1 - yc; double radius = sqrt((double)(dx * dx + dy * dy)); wxCoord rad = (wxCoord)radius; - double sa, ea; + double sa, ea; // In radians if (x1 == x2 && y1 == y2) { sa = 0.0; - ea = 360.0; + ea = 2.0 * M_PI; } else if (radius == 0.0) { @@ -699,11 +693,11 @@ void wxGCDCImpl::DoDrawArc( wxCoord x1, wxCoord y1, else { sa = (x1 - xc == 0) ? - (y1 - yc < 0) ? 90.0 : -90.0 : - -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG; + (y1 - yc < 0) ? M_PI / 2.0 : -M_PI / 2.0 : + -atan2(double(y1 - yc), double(x1 - xc)); ea = (x2 - xc == 0) ? - (y2 - yc < 0) ? 90.0 : -90.0 : - -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG; + (y2 - yc < 0) ? M_PI / 2.0 : -M_PI / 2.0 : + -atan2(double(y2 - yc), double(x2 - xc)); } bool fill = m_brush.GetStyle() != wxBRUSHSTYLE_TRANSPARENT; @@ -713,7 +707,7 @@ void wxGCDCImpl::DoDrawArc( wxCoord x1, wxCoord y1, path.MoveToPoint( xc, yc ); // since these angles (ea,sa) are measured counter-clockwise, we invert them to // get clockwise angles - path.AddArc( xc, yc , rad, wxDegToRad(-sa), wxDegToRad(-ea), false ); + path.AddArc( xc, yc , rad, -sa, -ea, false ); if ( fill && ((x1!=x2)||(y1!=y2)) ) path.AddLineToPoint( xc, yc ); m_graphicContext->DrawPath(path); From fe064de26bd643278e0c5f56ce327e0326fb51bc Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 4 Oct 2020 21:47:43 +0200 Subject: [PATCH 075/105] Use dedicated functions to convert between degrees and radians --- samples/drawing/drawing.cpp | 4 ++-- src/common/geometry.cpp | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/samples/drawing/drawing.cpp b/samples/drawing/drawing.cpp index a278e6a204..89e785a6ba 100644 --- a/samples/drawing/drawing.cpp +++ b/samples/drawing/drawing.cpp @@ -1338,8 +1338,8 @@ void MyCanvas::DrawSplines(wxDC& dc) { angle += angles[ angle_pos ]; int r = R * radii[ radius_pos ] / 100; - pts[ i ].x = center.x + (wxCoord)( r * cos( M_PI * angle / 180.0) ); - pts[ i ].y = center.y + (wxCoord)( r * sin( M_PI * angle / 180.0) ); + pts[ i ].x = center.x + (wxCoord)( r * cos(wxDegToRad(angle)) ); + pts[ i ].y = center.y + (wxCoord)( r * sin(wxDegToRad(angle)) ); angle_pos++; if ( angle_pos >= WXSIZEOF(angles) ) angle_pos = 0; diff --git a/src/common/geometry.cpp b/src/common/geometry.cpp index 57bdcb40c7..cd2fc3c59f 100644 --- a/src/common/geometry.cpp +++ b/src/common/geometry.cpp @@ -176,8 +176,7 @@ wxDouble wxPoint2DInt::GetVectorAngle() const return 180; } - // casts needed for MIPSpro compiler under SGI - wxDouble deg = atan2( (double)m_y , (double)m_x ) * 180 / M_PI; + wxDouble deg = wxRadToDeg(atan2( (double)m_y , (double)m_x )); if ( deg < 0 ) { deg += 360; @@ -189,8 +188,9 @@ wxDouble wxPoint2DInt::GetVectorAngle() const void wxPoint2DInt::SetVectorAngle( wxDouble degrees ) { wxDouble length = GetVectorLength(); - m_x = (int)(length * cos( degrees / 180 * M_PI )); - m_y = (int)(length * sin( degrees / 180 * M_PI )); + double rad = wxDegToRad(degrees); + m_x = (int)(length * cos(rad)); + m_y = (int)(length * sin(rad)); } wxDouble wxPoint2DDouble::GetVectorAngle() const @@ -209,7 +209,7 @@ wxDouble wxPoint2DDouble::GetVectorAngle() const else return 180; } - wxDouble deg = atan2( m_y , m_x ) * 180 / M_PI; + wxDouble deg = wxRadToDeg(atan2( m_y , m_x )); if ( deg < 0 ) { deg += 360; @@ -220,8 +220,9 @@ wxDouble wxPoint2DDouble::GetVectorAngle() const void wxPoint2DDouble::SetVectorAngle( wxDouble degrees ) { wxDouble length = GetVectorLength(); - m_x = length * cos( degrees / 180 * M_PI ); - m_y = length * sin( degrees / 180 * M_PI ); + double rad = wxDegToRad(degrees); + m_x = length * cos(rad); + m_y = length * sin(rad); } // wxRect2D From 4832565e1034b7b747d0252289698e2d47e73ce6 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Mon, 5 Oct 2020 15:21:35 +0300 Subject: [PATCH 076/105] Rename IsFallbackEncoding() to IsUsingFallbackEncoding() --- include/wx/convauto.h | 2 +- interface/wx/convauto.h | 2 +- tests/mbconv/convautotest.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/wx/convauto.h b/include/wx/convauto.h index 57212ab1ad..d7ed45592f 100644 --- a/include/wx/convauto.h +++ b/include/wx/convauto.h @@ -96,7 +96,7 @@ public: wxFontEncoding GetEncoding() const; // Return true if the fall-back encoding is used - bool IsFallbackEncoding() const + bool IsUsingFallbackEncoding() const { return m_ownsConv && m_bomType == wxBOM_None; } diff --git a/interface/wx/convauto.h b/interface/wx/convauto.h index 788d6ec2b9..324b5b24e7 100644 --- a/interface/wx/convauto.h +++ b/interface/wx/convauto.h @@ -160,7 +160,7 @@ public: @since 3.1.5 */ - bool IsFallbackEncoding() const; + bool IsUsingFallbackEncoding() const; /** Return a pointer to the characters that makes up this BOM. diff --git a/tests/mbconv/convautotest.cpp b/tests/mbconv/convautotest.cpp index 789e7582aa..6eaa24b155 100644 --- a/tests/mbconv/convautotest.cpp +++ b/tests/mbconv/convautotest.cpp @@ -69,7 +69,7 @@ private: { CPPUNIT_ASSERT( conv.GetBOM() == m_bom ); CPPUNIT_ASSERT( conv.GetEncoding() == m_enc ); - CPPUNIT_ASSERT( conv.IsFallbackEncoding() == m_fallback ); + CPPUNIT_ASSERT( conv.IsUsingFallbackEncoding() == m_fallback ); CPPUNIT_ASSERT( conv.IsUTF8() == (m_enc == wxFONTENCODING_UTF8) ); } From 307a0916fd7581870d40b920d776dec7ff60e8e7 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Mon, 5 Oct 2020 15:29:11 +0300 Subject: [PATCH 077/105] Add comment about 2 extra bytes in wxConvAuto::ToWChar --- src/common/convauto.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp index d5d6079b32..f63d015c83 100644 --- a/src/common/convauto.cpp +++ b/src/common/convauto.cpp @@ -313,6 +313,8 @@ wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, // to the fall-back conversion in this case as it would prevent us from // decoding UTF-8 input when fed it byte by byte, as done by // wxTextInputStream, for example + // 2 extra bytes are needed for inputs that start with 1 or 2 null bytes + // that look like the start of UTF-32BE BOM, but can be in UTF-8 too if ( srcLen < 2 + m_conv->GetMaxCharLen() && wxIsUTF8Prefix(src, srcLen) ) return wxCONV_FAILED; From 737e9be2d02d07e3ce0e94e51ca78d3afb4b3f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Mon, 5 Oct 2020 14:45:35 +0200 Subject: [PATCH 078/105] CMake: use same location for web-extensions as Bakefile Fix the location where the web-extension plugin is installed to be consistent with the primary bakefile-based build system: i.e. to use lib/wx/x.y.z for devel versions and lib/wx/x.y for stable. --- build/cmake/lib/webview/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build/cmake/lib/webview/CMakeLists.txt b/build/cmake/lib/webview/CMakeLists.txt index dc9850fa27..721a215bac 100644 --- a/build/cmake/lib/webview/CMakeLists.txt +++ b/build/cmake/lib/webview/CMakeLists.txt @@ -26,7 +26,11 @@ endif() wx_add_library(wxwebview ${WEBVIEW_FILES}) if(WXGTK AND wxUSE_WEBVIEW_WEBKIT2) - set(WX_WEB_EXTENSIONS_DIRECTORY "lib/wx/${wxMAJOR_VERSION}.${wxMINOR_VERSION}/web-extensions") + if(wxVERSION_IS_DEV) + set(WX_WEB_EXTENSIONS_DIRECTORY "lib/wx/${wxMAJOR_VERSION}.${wxMINOR_VERSION}.${wxRELEASE_NUMBER}/web-extensions") + else() + set(WX_WEB_EXTENSIONS_DIRECTORY "lib/wx/${wxMAJOR_VERSION}.${wxMINOR_VERSION}/web-extensions") + endif() wx_lib_compile_definitions(wxwebview PRIVATE -DWX_WEB_EXTENSIONS_DIRECTORY="${CMAKE_INSTALL_PREFIX}/${WX_WEB_EXTENSIONS_DIRECTORY}" ) From 40e5152cfcfdd0cee56db94f404d7699767583cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Mon, 5 Oct 2020 16:54:07 +0200 Subject: [PATCH 079/105] Remove WX_WEB_EXTENSIONS_DIRECTORY define wxWidgets already has a mechanism for locating plugins under $libdir/wx/*, there's no reason to duplicate it with another compile-time symbol. As a consequence, this makes the library relocatable via WXPREFIX again. --- Makefile.in | 46 ++++++++++---------------- autoconf_inc.m4 | 2 +- build/bakefiles/common.bkl | 5 --- build/bakefiles/monolithic.bkl | 2 -- build/bakefiles/multilib.bkl | 2 -- build/cmake/lib/webview/CMakeLists.txt | 3 -- src/common/dynlib.cpp | 2 ++ src/gtk/webview_webkit2.cpp | 21 +++++++----- 8 files changed, 33 insertions(+), 50 deletions(-) diff --git a/Makefile.in b/Makefile.in index 62beaa8482..74838af176 100644 --- a/Makefile.in +++ b/Makefile.in @@ -949,8 +949,8 @@ MONODLL_CFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \ -I$(top_srcdir)/src/stc/scintilla/include \ -I$(top_srcdir)/src/stc/scintilla/lexlib \ -I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \ - -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(__webviewdll_ext_dir_define_p) \ - $(PIC_FLAG) $(WX_CFLAGS) $(CPPFLAGS) $(CFLAGS) + -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(PIC_FLAG) $(WX_CFLAGS) \ + $(CPPFLAGS) $(CFLAGS) MONODLL_CXXFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \ $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) $(__INC_REGEX_p) \ $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \ @@ -959,8 +959,8 @@ MONODLL_CXXFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \ -I$(top_srcdir)/src/stc/scintilla/include \ -I$(top_srcdir)/src/stc/scintilla/lexlib \ -I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \ - -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(__webviewdll_ext_dir_define_p) \ - $(PIC_FLAG) $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS) + -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(PIC_FLAG) $(WX_CXXFLAGS) \ + $(CPPFLAGS) $(CXXFLAGS) MONODLL_OBJCXXFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) \ $(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \ $(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \ @@ -969,8 +969,8 @@ MONODLL_OBJCXXFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) \ -I$(top_srcdir)/src/stc/scintilla/include \ -I$(top_srcdir)/src/stc/scintilla/lexlib \ -I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \ - -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(__webviewdll_ext_dir_define_p) \ - $(PIC_FLAG) $(CPPFLAGS) $(OBJCXXFLAGS) + -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(PIC_FLAG) $(CPPFLAGS) \ + $(OBJCXXFLAGS) MONODLL_OBJECTS = \ monodll_any.o \ monodll_appbase.o \ @@ -1092,8 +1092,7 @@ MONOLIB_CFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \ -I$(top_srcdir)/src/stc/scintilla/include \ -I$(top_srcdir)/src/stc/scintilla/lexlib \ -I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \ - -DLINK_LEXERS -DwxUSE_BASE=1 $(__webviewdll_ext_dir_define_p) $(WX_CFLAGS) \ - $(CPPFLAGS) $(CFLAGS) + -DLINK_LEXERS -DwxUSE_BASE=1 $(WX_CFLAGS) $(CPPFLAGS) $(CFLAGS) MONOLIB_CXXFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \ $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) $(__INC_REGEX_p) \ $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \ @@ -1102,8 +1101,7 @@ MONOLIB_CXXFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \ -I$(top_srcdir)/src/stc/scintilla/include \ -I$(top_srcdir)/src/stc/scintilla/lexlib \ -I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \ - -DLINK_LEXERS -DwxUSE_BASE=1 $(__webviewdll_ext_dir_define_p) \ - $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS) + -DLINK_LEXERS -DwxUSE_BASE=1 $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS) MONOLIB_OBJCXXFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) \ $(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \ $(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \ @@ -1112,8 +1110,7 @@ MONOLIB_OBJCXXFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) \ -I$(top_srcdir)/src/stc/scintilla/include \ -I$(top_srcdir)/src/stc/scintilla/lexlib \ -I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \ - -DLINK_LEXERS -DwxUSE_BASE=1 $(__webviewdll_ext_dir_define_p) $(CPPFLAGS) \ - $(OBJCXXFLAGS) + -DLINK_LEXERS -DwxUSE_BASE=1 $(CPPFLAGS) $(OBJCXXFLAGS) MONOLIB_OBJECTS = \ monolib_any.o \ monolib_appbase.o \ @@ -1669,16 +1666,15 @@ WEBVIEWDLL_CXXFLAGS = $(__webviewdll_PCH_INC) $(__INC_TIFF_BUILD_p) \ $(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) \ $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) -DWXBUILDING -DWXUSINGDLL \ - -DWXMAKINGDLL_WEBVIEW $(__webviewdll_ext_dir_define_p) \ - $(__webview_additional_include_p) $(PIC_FLAG) $(WX_CXXFLAGS) $(CPPFLAGS) \ - $(CXXFLAGS) + -DWXMAKINGDLL_WEBVIEW $(__webview_additional_include_p) $(PIC_FLAG) \ + $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS) WEBVIEWDLL_OBJCXXFLAGS = $(__webviewdll_PCH_INC) $(__INC_TIFF_BUILD_p) \ $(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \ $(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) \ $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) -DWXBUILDING -DWXUSINGDLL \ - -DWXMAKINGDLL_WEBVIEW $(__webviewdll_ext_dir_define_p) \ - $(__webview_additional_include_p) $(PIC_FLAG) $(CPPFLAGS) $(OBJCXXFLAGS) + -DWXMAKINGDLL_WEBVIEW $(__webview_additional_include_p) $(PIC_FLAG) \ + $(CPPFLAGS) $(OBJCXXFLAGS) WEBVIEWDLL_OBJECTS = \ $(__WEBVIEW_SRC_PLATFORM_OBJECTS_2) \ webviewdll_webview.o \ @@ -1691,15 +1687,13 @@ WEBVIEWLIB_CXXFLAGS = $(__webviewlib_PCH_INC) $(__INC_TIFF_BUILD_p) \ $(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) \ $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) -DWXBUILDING \ - $(__webviewdll_ext_dir_define_p) $(__webview_additional_include_p) \ - $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS) + $(__webview_additional_include_p) $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS) WEBVIEWLIB_OBJCXXFLAGS = $(__webviewlib_PCH_INC) $(__INC_TIFF_BUILD_p) \ $(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \ $(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) \ $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) -DWXBUILDING \ - $(__webviewdll_ext_dir_define_p) $(__webview_additional_include_p) \ - $(CPPFLAGS) $(OBJCXXFLAGS) + $(__webview_additional_include_p) $(CPPFLAGS) $(OBJCXXFLAGS) WEBVIEWLIB_OBJECTS = \ $(__WEBVIEW_SRC_PLATFORM_OBJECTS_3) \ webviewlib_webview.o \ @@ -13341,9 +13335,6 @@ COND_PLATFORM_MACOSX_1___OSX_LOWLEVEL_SRC_OBJECTS = \ monodll_core_timer.o \ monodll_utilsexc_cf.o @COND_PLATFORM_MACOSX_1@__OSX_LOWLEVEL_SRC_OBJECTS = $(COND_PLATFORM_MACOSX_1___OSX_LOWLEVEL_SRC_OBJECTS) -COND_USE_WEBVIEW_WEBKIT2_1___webviewdll_ext_dir_define_p_0 = --define \ - WX_WEB_EXTENSIONS_DIRECTORY=\"$(PLUGINS_INST_DIR)/web-extensions\" -@COND_USE_WEBVIEW_WEBKIT2_1@__webviewdll_ext_dir_define_p_0 = $(COND_USE_WEBVIEW_WEBKIT2_1___webviewdll_ext_dir_define_p_0) @COND_PLATFORM_MACOSX_1@__PLATFORM_SRC_OBJECTS_0 = monolib_unix_apptraits.o @COND_PLATFORM_UNIX_1@__PLATFORM_SRC_OBJECTS_0 = monolib_unix_apptraits.o COND_PLATFORM_MACOSX_1___OSX_COMMON_SRC_OBJECTS_0 = \ @@ -13758,9 +13749,6 @@ COND_PLATFORM_MACOSX_1___OSX_LOWLEVEL_SRC_OBJECTS_1_4 = \ corelib_core_timer.o \ corelib_utilsexc_cf.o @COND_PLATFORM_MACOSX_1@__OSX_LOWLEVEL_SRC_OBJECTS_1_4 = $(COND_PLATFORM_MACOSX_1___OSX_LOWLEVEL_SRC_OBJECTS_1_4) -@COND_USE_WEBVIEW_WEBKIT2_1@__webviewdll_ext_dir_define_p \ -@COND_USE_WEBVIEW_WEBKIT2_1@ = \ -@COND_USE_WEBVIEW_WEBKIT2_1@ -DWX_WEB_EXTENSIONS_DIRECTORY=\"$(PLUGINS_INST_DIR)/web-extensions\" @COND_TOOLKIT_MSW@__webview_additional_include_p = \ @COND_TOOLKIT_MSW@ -I$(top_srcdir)/3rdparty/webview2/build/native/include @COND_MONOLITHIC_0_SHARED_1_USE_GUI_1_USE_HTML_1@__htmldll_library_link_DEP \ @@ -20872,7 +20860,7 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP) @COND_PLATFORM_MACOSX_1_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/html/chm.cpp monodll_version_rc.o: $(srcdir)/src/msw/version.rc $(MONODLL_ODEP) - $(WINDRES) -i$< -o$@ $(__INC_TIFF_BUILD_p_54) $(__INC_TIFF_p_54) $(__INC_JPEG_p_54) $(__INC_PNG_p_53) $(__INC_ZLIB_p_67) $(__INC_REGEX_p_65) $(__INC_EXPAT_p_65) --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_67) $(__DEBUG_DEFINE_p_66) $(__EXCEPTIONS_DEFINE_p_65) $(__RTTI_DEFINE_p_65) $(__THREAD_DEFINE_p_65) --define WXBUILDING --define WXDLLNAME=$(WXDLLNAMEPREFIXGUI)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)$(WXCOMPILER)$(VENDORTAG)$(WXDLLVERSIONTAG) $(__RCDEFDIR_p) --include-dir $(top_srcdir)/include --include-dir $(top_srcdir)/src/stc/scintilla/include --include-dir $(top_srcdir)/src/stc/scintilla/lexlib --include-dir $(top_srcdir)/src/stc/scintilla/src --define __WX__ --define SCI_LEXER --define NO_CXX11_REGEX --define LINK_LEXERS --define wxUSE_BASE=1 --define WXMAKINGDLL $(__webviewdll_ext_dir_define_p_0) + $(WINDRES) -i$< -o$@ $(__INC_TIFF_BUILD_p_54) $(__INC_TIFF_p_54) $(__INC_JPEG_p_54) $(__INC_PNG_p_53) $(__INC_ZLIB_p_67) $(__INC_REGEX_p_65) $(__INC_EXPAT_p_65) --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_67) $(__DEBUG_DEFINE_p_66) $(__EXCEPTIONS_DEFINE_p_65) $(__RTTI_DEFINE_p_65) $(__THREAD_DEFINE_p_65) --define WXBUILDING --define WXDLLNAME=$(WXDLLNAMEPREFIXGUI)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)$(WXCOMPILER)$(VENDORTAG)$(WXDLLVERSIONTAG) $(__RCDEFDIR_p) --include-dir $(top_srcdir)/include --include-dir $(top_srcdir)/src/stc/scintilla/include --include-dir $(top_srcdir)/src/stc/scintilla/lexlib --include-dir $(top_srcdir)/src/stc/scintilla/src --define __WX__ --define SCI_LEXER --define NO_CXX11_REGEX --define LINK_LEXERS --define wxUSE_BASE=1 --define WXMAKINGDLL monolib_any.o: $(srcdir)/src/common/any.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/any.cpp @@ -36010,7 +35998,7 @@ webviewdll_webviewfshandler.o: $(srcdir)/src/common/webviewfshandler.cpp $(WEBVI $(CXXC) -c -o $@ $(WEBVIEWDLL_CXXFLAGS) $(srcdir)/src/common/webviewfshandler.cpp webviewdll_version_rc.o: $(srcdir)/src/msw/version.rc $(WEBVIEWDLL_ODEP) - $(WINDRES) -i$< -o$@ $(__INC_TIFF_BUILD_p_54) $(__INC_TIFF_p_54) $(__INC_JPEG_p_54) $(__INC_PNG_p_53) $(__INC_ZLIB_p_67) $(__INC_REGEX_p_65) $(__INC_EXPAT_p_65) --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_67) $(__DEBUG_DEFINE_p_66) $(__EXCEPTIONS_DEFINE_p_65) $(__RTTI_DEFINE_p_65) $(__THREAD_DEFINE_p_65) --define WXBUILDING --define WXDLLNAME=$(WXDLLNAMEPREFIXGUI)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_webview$(WXCOMPILER)$(VENDORTAG)$(WXDLLVERSIONTAG) $(__RCDEFDIR_p) --include-dir $(top_srcdir)/include --define WXUSINGDLL --define WXMAKINGDLL_WEBVIEW $(__webviewdll_ext_dir_define_p_0) $(__webview_additional_include_p_1) + $(WINDRES) -i$< -o$@ $(__INC_TIFF_BUILD_p_54) $(__INC_TIFF_p_54) $(__INC_JPEG_p_54) $(__INC_PNG_p_53) $(__INC_ZLIB_p_67) $(__INC_REGEX_p_65) $(__INC_EXPAT_p_65) --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_67) $(__DEBUG_DEFINE_p_66) $(__EXCEPTIONS_DEFINE_p_65) $(__RTTI_DEFINE_p_65) $(__THREAD_DEFINE_p_65) --define WXBUILDING --define WXDLLNAME=$(WXDLLNAMEPREFIXGUI)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_webview$(WXCOMPILER)$(VENDORTAG)$(WXDLLVERSIONTAG) $(__RCDEFDIR_p) --include-dir $(top_srcdir)/include --define WXUSINGDLL --define WXMAKINGDLL_WEBVIEW $(__webview_additional_include_p_1) webviewlib_webview_ie.o: $(srcdir)/src/msw/webview_ie.cpp $(WEBVIEWLIB_ODEP) $(CXXC) -c -o $@ $(WEBVIEWLIB_CXXFLAGS) $(srcdir)/src/msw/webview_ie.cpp diff --git a/autoconf_inc.m4 b/autoconf_inc.m4 index eae0f23231..9f06e653b9 100644 --- a/autoconf_inc.m4 +++ b/autoconf_inc.m4 @@ -980,7 +980,7 @@ dnl ### begin block 20_COND_USE_THREADS_1[../../demos/bombs/bombs.bkl,../../demo COND_USE_THREADS_1="" fi AC_SUBST(COND_USE_THREADS_1) -dnl ### begin block 20_COND_USE_WEBVIEW_WEBKIT2_1[../../demos/bombs/bombs.bkl,../../demos/forty/forty.bkl,../../demos/fractal/fractal.bkl,../../demos/life/life.bkl,../../demos/poem/poem.bkl,../../samples/access/access.bkl,../../samples/animate/anitest.bkl,../../samples/archive/archive.bkl,../../samples/artprov/artprov.bkl,../../samples/aui/auidemo.bkl,../../samples/calendar/calendar.bkl,../../samples/caret/caret.bkl,../../samples/clipboard/clipboard.bkl,../../samples/collpane/collpane.bkl,../../samples/combo/combo.bkl,../../samples/config/config.bkl,../../samples/console/console.bkl,../../samples/dataview/dataview.bkl,../../samples/debugrpt/debugrpt.bkl,../../samples/dialogs/dialogs.bkl,../../samples/dialup/dialup.bkl,../../samples/display/display.bkl,../../samples/dll/dll.bkl,../../samples/dnd/dnd.bkl,../../samples/docview/docview.bkl,../../samples/dragimag/dragimag.bkl,../../samples/drawing/drawing.bkl,../../samples/erase/erase.bkl,../../samples/event/event.bkl,../../samples/except/except.bkl,../../samples/exec/exec.bkl,../../samples/font/font.bkl,../../samples/fswatcher/fswatcher.bkl,../../samples/grid/grid.bkl,../../samples/help/help.bkl,../../samples/htlbox/htlbox.bkl,../../samples/html/about/about.bkl,../../samples/html/help/help.bkl,../../samples/html/helpview/helpview.bkl,../../samples/html/htmlctrl/htmlctrl.bkl,../../samples/html/printing/printing.bkl,../../samples/html/test/test.bkl,../../samples/html/virtual/virtual.bkl,../../samples/html/widget/widget.bkl,../../samples/html/zip/zip.bkl,../../samples/image/image.bkl,../../samples/internat/internat.bkl,../../samples/ipc/ipc.bkl,../../samples/joytest/joytest.bkl,../../samples/keyboard/keyboard.bkl,../../samples/layout/layout.bkl,../../samples/listctrl/listctrl.bkl,../../samples/mdi/mdi.bkl,../../samples/mediaplayer/mediaplayer.bkl,../../samples/memcheck/memcheck.bkl,../../samples/menu/menu.bkl,../../samples/minimal/minimal.bkl,../../samples/nativdlg/nativdlg.bkl,../../samples/notebook/notebook.bkl,../../samples/oleauto/oleauto.bkl,../../samples/opengl/cube/cube.bkl,../../samples/opengl/isosurf/isosurf.bkl,../../samples/opengl/penguin/penguin.bkl,../../samples/opengl/pyramid/pyramid.bkl,../../samples/ownerdrw/ownerdrw.bkl,../../samples/popup/popup.bkl,../../samples/power/power.bkl,../../samples/preferences/preferences.bkl,../../samples/printing/printing.bkl,../../samples/propgrid/propgrid.bkl,../../samples/regtest/regtest.bkl,../../samples/render/render.bkl,../../samples/ribbon/ribbon.bkl,../../samples/richtext/richtext.bkl,../../samples/sashtest/sashtest.bkl,../../samples/scroll/scroll.bkl,../../samples/secretstore/secretstore.bkl,../../samples/shaped/shaped.bkl,../../samples/sockets/sockets.bkl,../../samples/sound/sound.bkl,../../samples/splash/splash.bkl,../../samples/splitter/splitter.bkl,../../samples/statbar/statbar.bkl,../../samples/stc/stctest.bkl,../../samples/svg/svgtest.bkl,../../samples/taborder/taborder.bkl,../../samples/taskbar/taskbar.bkl,../../samples/taskbarbutton/taskbarbutton.bkl,../../samples/text/text.bkl,../../samples/thread/thread.bkl,../../samples/toolbar/toolbar.bkl,../../samples/treectrl/treectrl.bkl,../../samples/treelist/treelist.bkl,../../samples/typetest/typetest.bkl,../../samples/uiaction/uiaction.bkl,../../samples/validate/validate.bkl,../../samples/vscroll/vscroll.bkl,../../samples/webview/webview.bkl,../../samples/widgets/widgets.bkl,../../samples/wizard/wizard.bkl,../../samples/wrapsizer/wrapsizer.bkl,../../samples/xrc/xrcdemo.bkl,../../samples/xti/xti.bkl,../../tests/benchmarks/bench.bkl,../../tests/test.bkl,../../utils/emulator/src/emulator.bkl,../../utils/execmon/execmon.bkl,../../utils/helpview/src/helpview.bkl,../../utils/hhp2cached/hhp2cached.bkl,../../utils/ifacecheck/src/ifacecheck.bkl,../../utils/screenshotgen/src/screenshotgen.bkl,../../utils/wxrc/wxrc.bkl,wx.bkl] ### +dnl ### begin block 20_COND_USE_WEBVIEW_WEBKIT2_1[wx.bkl] ### COND_USE_WEBVIEW_WEBKIT2_1="#" if test "x$USE_WEBVIEW_WEBKIT2" = "x1" ; then COND_USE_WEBVIEW_WEBKIT2_1="" diff --git a/build/bakefiles/common.bkl b/build/bakefiles/common.bkl index e22e718bbb..62748bbb32 100644 --- a/build/bakefiles/common.bkl +++ b/build/bakefiles/common.bkl @@ -897,9 +897,4 @@ $(TAB)cl /EP /nologo "$(DOLLAR)(InputPath)" > "$(SETUPHDIR)\wx\msw\rcdefs.h" top_srcdir - - WX_WEB_EXTENSIONS_DIRECTORY=\"$(PLUGINS_INST_DIR)/web-extensions\" - - - diff --git a/build/bakefiles/monolithic.bkl b/build/bakefiles/monolithic.bkl index 278a308af4..90cdc085ed 100644 --- a/build/bakefiles/monolithic.bkl +++ b/build/bakefiles/monolithic.bkl @@ -28,7 +28,6 @@ WXMAKINGDLL - $(webviewdll_ext_dir_define) $(EXTRALIBS_XML) $(EXTRALIBS_HTML) $(EXTRALIBS_MEDIA) @@ -40,7 +39,6 @@ - $(webviewdll_ext_dir_define) 8192 diff --git a/build/bakefiles/multilib.bkl b/build/bakefiles/multilib.bkl index 3367df44bc..c378688dd7 100644 --- a/build/bakefiles/multilib.bkl +++ b/build/bakefiles/multilib.bkl @@ -184,7 +184,6 @@ cond="SHARED=='1' and USE_GUI=='1' and USE_WEBVIEW=='1' and MONOLITHIC=='0'"> WXUSINGDLL WXMAKINGDLL_WEBVIEW - $(webviewdll_ext_dir_define) $(WEBVIEW_SRC) coredll basedll @@ -195,7 +194,6 @@ - $(webviewdll_ext_dir_define) $(WEBVIEW_SRC) $(WEBVIEW_HDR) $(webview_additional_include) diff --git a/build/cmake/lib/webview/CMakeLists.txt b/build/cmake/lib/webview/CMakeLists.txt index 721a215bac..1e2e7057a9 100644 --- a/build/cmake/lib/webview/CMakeLists.txt +++ b/build/cmake/lib/webview/CMakeLists.txt @@ -31,9 +31,6 @@ if(WXGTK AND wxUSE_WEBVIEW_WEBKIT2) else() set(WX_WEB_EXTENSIONS_DIRECTORY "lib/wx/${wxMAJOR_VERSION}.${wxMINOR_VERSION}/web-extensions") endif() - wx_lib_compile_definitions(wxwebview PRIVATE - -DWX_WEB_EXTENSIONS_DIRECTORY="${CMAKE_INSTALL_PREFIX}/${WX_WEB_EXTENSIONS_DIRECTORY}" - ) endif() if(APPLE) diff --git a/src/common/dynlib.cpp b/src/common/dynlib.cpp index 37fea09768..8130f93f9d 100644 --- a/src/common/dynlib.cpp +++ b/src/common/dynlib.cpp @@ -227,6 +227,8 @@ wxString wxDynamicLibrary::GetPluginsDirectory() { #ifdef __UNIX__ wxString format = wxGetInstallPrefix(); + if ( format.empty() ) + return wxEmptyString; wxString dir; format << wxFILE_SEP_PATH << wxT("lib") << wxFILE_SEP_PATH diff --git a/src/gtk/webview_webkit2.cpp b/src/gtk/webview_webkit2.cpp index 69583a546a..72351dd8e5 100644 --- a/src/gtk/webview_webkit2.cpp +++ b/src/gtk/webview_webkit2.cpp @@ -369,7 +369,7 @@ wxgtk_webview_webkit_counted_matches(WebKitFindController *, } // This function checks if the specified directory contains our web extension. -static bool CheckDirectoryForWebExt(const char* dirname) +static bool CheckDirectoryForWebExt(const wxString& dirname) { wxDir dir; if ( !wxDir::Exists(dirname) || !dir.Open(dirname) ) @@ -409,33 +409,38 @@ wxgtk_initialize_web_extensions(WebKitWebContext *context, // The first value is the location in which the extension is supposed to be // normally installed, while the other three are used as fallbacks to allow // running the tests and sample using wxWebView before installing it. - const char* const directories[] = + + wxString normalLocation = wxDynamicLibrary::GetPluginsDirectory(); + if ( !normalLocation.empty() ) + normalLocation += "/web-extensions"; + + wxString const directories[] = { - WX_WEB_EXTENSIONS_DIRECTORY, + normalLocation, "..", "../..", "lib", }; - const char* dir = NULL; + wxString dir; for ( size_t n = 0; n < WXSIZEOF(directories); ++n ) { - if ( CheckDirectoryForWebExt(directories[n]) ) + if ( !directories[n].empty() && CheckDirectoryForWebExt(directories[n]) ) { dir = directories[n]; break; } } - if ( dir ) + if ( !dir.empty() ) { - webkit_web_context_set_web_extensions_directory(context, dir); + webkit_web_context_set_web_extensions_directory(context, dir.utf8_str()); } else { wxLogWarning(_("Web extension not found in \"%s\", " "some wxWebView functionality will be not available"), - WX_WEB_EXTENSIONS_DIRECTORY); + directories[0]); } webkit_web_context_set_web_extensions_initialization_user_data(context, From 301e5ec9fe3719fac8a2786e8675b19e2242183e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Mon, 5 Oct 2020 17:01:28 +0200 Subject: [PATCH 080/105] Fix autogen.mk after e70fc11e cppunit.m4 was removed, don't fail if it's missing. --- build/autogen.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/build/autogen.mk b/build/autogen.mk index f72b447808..537a3f5438 100644 --- a/build/autogen.mk +++ b/build/autogen.mk @@ -56,7 +56,6 @@ ACLOCAL_SOURCES = \ build/aclocal/ax_func_which_gethostbyname_r.m4 \ build/aclocal/bakefile-lang.m4 \ build/aclocal/bakefile.m4 \ - build/aclocal/cppunit.m4 \ build/aclocal/gst-element-check.m4 \ build/aclocal/gtk-2.0.m4 \ build/aclocal/gtk.m4 \ From 633165fd13d2fdb0a530affdd5c78873d84d4023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Mon, 5 Oct 2020 17:03:45 +0200 Subject: [PATCH 081/105] Log stale lock files in verbose mode only Actually do what the comment says is intended. wxLogInfo() and wxLogVerbose() differ in that only the latter must be explicitly enabled with --verbose. --- src/unix/snglinst.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/snglinst.cpp b/src/unix/snglinst.cpp index 0c8d4275ef..9c64ffbf6f 100644 --- a/src/unix/snglinst.cpp +++ b/src/unix/snglinst.cpp @@ -298,7 +298,7 @@ bool wxSingleInstanceCheckerImpl::Create(const wxString& name) // message is that the previous instance of the program // crashed), don't show it by default, i.e. unless the // program is running with --verbose command line option. - wxLogInfo(_("Deleted stale lock file '%s'."), + wxLogVerbose(_("Deleted stale lock file '%s'."), name.c_str()); // retry now From d2e7b5bdd1610b97732e7bcca4f3b4f2db2bd145 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Mon, 5 Oct 2020 18:10:27 +0300 Subject: [PATCH 082/105] Fix GetEncoding() after global fallback encoding is changed Save global fallback encoding when switching to it, so GetEncoding() can still return the correct value if global fallback encoding is changed later. Also do not switch to wxFONTENCODING_MAX when it is set as global fallback encoding. --- src/common/convauto.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp index f63d015c83..840841f5b6 100644 --- a/src/common/convauto.cpp +++ b/src/common/convauto.cpp @@ -320,11 +320,11 @@ wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, // if the conversion failed but we didn't really detect anything and // simply tried UTF-8 by default, retry it using the fall-back + if ( m_encDefault == wxFONTENCODING_DEFAULT ) + self->m_encDefault = GetFallbackEncoding(); if ( m_encDefault != wxFONTENCODING_MAX ) { - self->m_conv = new wxCSConv(m_encDefault == wxFONTENCODING_DEFAULT - ? GetFallbackEncoding() - : m_encDefault); + self->m_conv = new wxCSConv(m_encDefault); self->m_ownsConv = true; rc = m_conv->ToWChar(dst, dstLen, src, srcLen); @@ -372,10 +372,8 @@ wxFontEncoding wxConvAuto::GetEncoding() const return wxFONTENCODING_MAX; else if ( !m_ownsConv ) return wxFONTENCODING_UTF8; - else if ( m_encDefault != wxFONTENCODING_DEFAULT ) - return m_encDefault; else - return GetFallbackEncoding(); + return m_encDefault; } wxFAIL_MSG( "unknown BOM type" ); From 5e57976bba24409080d3681f0a921884e4f937bb Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 4 Oct 2020 23:43:19 +0200 Subject: [PATCH 083/105] Don't use ID2D1Bitmap::GetSize() to get source bitmap size Closes https://github.com/wxWidgets/wxWidgets/pull/2074 See #17171, #18686. --- src/msw/graphicsd2d.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/msw/graphicsd2d.cpp b/src/msw/graphicsd2d.cpp index a436dd6243..cc6bdb08d4 100644 --- a/src/msw/graphicsd2d.cpp +++ b/src/msw/graphicsd2d.cpp @@ -4494,11 +4494,11 @@ void wxD2DContext::DrawBitmap(const wxGraphicsBitmap& bmp, wxDouble x, wxDouble wxD2DBitmapData* bitmapData = wxGetD2DBitmapData(bmp); bitmapData->Bind(this); - D2D1_SIZE_F imgSize = bitmapData->GetD2DBitmap()->GetSize(); + wxBitmap const& bitmap = static_cast(bitmapData->GetNativeBitmap())->GetSourceBitmap(); m_renderTargetHolder->DrawBitmap( bitmapData->GetD2DBitmap(), - D2D1::RectF(0, 0, imgSize.width, imgSize.height), + D2D1::RectF(0, 0, bitmap.GetWidth(), bitmap.GetHeight()), D2D1::RectF(x, y, x + w, y + h), GetInterpolationQuality(), GetCompositionMode()); From 23992c2e77494d1a715d848c8052d6717e6ec266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Mon, 5 Oct 2020 18:56:26 +0200 Subject: [PATCH 084/105] Fix implicit conversion loss warning in wx/math.h --- include/wx/math.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wx/math.h b/include/wx/math.h index 241c3841ea..8c39bb2aa5 100644 --- a/include/wx/math.h +++ b/include/wx/math.h @@ -68,7 +68,7 @@ wxASSERT_MSG(x > (double)INT_MIN - 0.5 && x < (double)INT_MAX + 0.5, wxT("argument out of supported range")); - return std::lround(x); + return (int)std::lround(x); } #else /* C++98 */ From cb5e0d221cf1f6cb63e956402f898138ed47f454 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 6 Oct 2020 00:22:55 +0200 Subject: [PATCH 085/105] Fix running new wxImage::Paste() unit tests from build directory Add new image test files added in 6e8da8641c (Add alpha blending for wxImage::Paste, 2020-09-23) and 1f0ade29f0 (Fix using mask colour even if there is no mask in wxImage::Paste, 2020-09-30) to Makefile, so that they're copied to the build directory and could be found by the test there, otherwise running wxImage::Paste test when building outside of the source directory failed. --- tests/Makefile.in | 2 +- tests/makefile.bcc | 2 +- tests/makefile.gcc | 2 +- tests/makefile.vc | 2 +- tests/test.bkl | 10 ++++++++++ 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/Makefile.in b/tests/Makefile.in index eb43137e9d..f99b4761e1 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -548,7 +548,7 @@ data: data-images: @mkdir -p image - @for f in horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png; do \ + @for f in horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png; do \ if test ! -f image/$$f -a ! -d image/$$f ; \ then x=yep ; \ else x=`find $(srcdir)/image/$$f -newer image/$$f -print` ; \ diff --git a/tests/makefile.bcc b/tests/makefile.bcc index 2a503e7998..b505662946 100644 --- a/tests/makefile.bcc +++ b/tests/makefile.bcc @@ -571,7 +571,7 @@ data: data-images: if not exist image mkdir image - for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png) do if not exist image\%f copy .\image\%f image + for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png) do if not exist image\%f copy .\image\%f image fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr diff --git a/tests/makefile.gcc b/tests/makefile.gcc index adfa87505e..c074804243 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -556,7 +556,7 @@ data: data-images: if not exist image mkdir image - for %%f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png) do if not exist image\%%f copy .\image\%%f image + for %%f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png) do if not exist image\%%f copy .\image\%%f image fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr diff --git a/tests/makefile.vc b/tests/makefile.vc index 4ba6a5643d..c5652c9a21 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -984,7 +984,7 @@ data: data-images: if not exist image mkdir image - for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png) do if not exist image\%f copy .\image\%f image + for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png) do if not exist image\%f copy .\image\%f image fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr diff --git a/tests/test.bkl b/tests/test.bkl index 74d0cc1c50..0aa49e95cd 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -360,6 +360,16 @@ cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png + + paste_input_background.png + paste_input_black.png + paste_input_overlay_transparent_border_opaque_square.png + paste_input_overlay_transparent_border_semitransparent_circle.png + paste_input_overlay_transparent_border_semitransparent_square.png + paste_result_background_plus_circle_plus_square.png + paste_result_background_plus_overlay_transparent_border_opaque_square.png + paste_result_background_plus_overlay_transparent_border_semitransparent_square.png + paste_result_no_background_square_over_circle.png From d58f9bea72380c30d2bd1a42e3a99e81eae908cd Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 6 Oct 2020 00:40:59 +0200 Subject: [PATCH 086/105] Rearrange sections in wxImage::Paste unit test No real changes, just execute only the tests relevant for the section being executed instead of always running the code loading PNG images when running a section not using them at all. This has the advantages of being a bit faster to execute (and the total test suite run time does add up) and, more importantly, showing the right amount of tests when executing a single section: e.g. now it's 1 in the simplest case, as expected, and not 5. The disadvantage is, of course, slightly more code duplication, but it doesn't seem a huge problem in practice and making each section code more self-contained is arguably worth it. Also, compensate for this somewhat by extracting all XPM definitions at the function level: those are only initialized once (being static), so there is no need to duplicate them. Finally, also call AddHandler() once instead of once per section as before. --- tests/image/image.cpp | 143 +++++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 58 deletions(-) diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 9f72e942b2..60248f0f76 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -1493,6 +1493,46 @@ TEST_CASE("wxImage::Paste", "[image][paste]") "y y y y y", }; + const static char* transparent_image_xpm[] = + { + "5 5 2 1", + " c None", // Mask + "y c #FFFF00", + " ", + " ", + " ", + " ", + " ", + }; + + const static char* light_image_xpm[] = + { + "5 5 2 1", + " c None", + "y c #FFFF00", + "yyyyy", + "yyyyy", + "yyyyy", + "yyyyy", + "yyyyy", + }; + + const static char* black_image_xpm[] = + { + "5 5 2 1", + " c #000000", + "y c None", // Mask + " ", + " ", + " ", + " ", + " ", + }; + + // Execute AddHandler() just once. + static const bool + registeredHandler = (wxImage::AddHandler(new wxPNGHandler()), true); + SECTION("Paste same size image") { wxImage actual(squares_xpm); @@ -1690,18 +1730,11 @@ TEST_CASE("wxImage::Paste", "[image][paste]") CHECK_THAT(actual, RGBSameAs(expected)); } - wxImage::AddHandler(new wxPNGHandler()); - wxImage background("image/paste_input_background.png"); - CHECK(background.IsOk()); - wxImage opaque_square("image/paste_input_overlay_transparent_border_opaque_square.png"); - CHECK(opaque_square.IsOk()); - wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png"); - CHECK(transparent_square.IsOk()); - wxImage transparent_circle("image/paste_input_overlay_transparent_border_semitransparent_circle.png"); - CHECK(transparent_circle.IsOk()); - SECTION("Paste fully opaque image onto blank image without alpha") { + const wxImage background("image/paste_input_background.png"); + REQUIRE(background.IsOk()); + wxImage actual(background.GetSize()); actual.Paste(background, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); CHECK_THAT(actual, RGBSameAs(background)); @@ -1709,6 +1742,9 @@ TEST_CASE("wxImage::Paste", "[image][paste]") } SECTION("Paste fully opaque image onto blank image with alpha") { + const wxImage background("image/paste_input_background.png"); + REQUIRE(background.IsOk()); + wxImage actual(background.GetSize()); actual.InitAlpha(); actual.Paste(background, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); @@ -1717,6 +1753,9 @@ TEST_CASE("wxImage::Paste", "[image][paste]") } SECTION("Paste fully transparent image") { + const wxImage background("image/paste_input_background.png"); + REQUIRE(background.IsOk()); + wxImage actual = background.Copy(); wxImage transparent(actual.GetSize()); transparent.InitAlpha(); @@ -1727,21 +1766,39 @@ TEST_CASE("wxImage::Paste", "[image][paste]") } SECTION("Paste image with transparent region") { - wxImage actual = background.Copy(); + wxImage actual("image/paste_input_background.png"); + REQUIRE(actual.IsOk()); + + const wxImage opaque_square("image/paste_input_overlay_transparent_border_opaque_square.png"); + REQUIRE(opaque_square.IsOk()); + actual.Paste(opaque_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); CHECK_THAT(actual, RGBSameAs(wxImage("image/paste_result_background_plus_overlay_transparent_border_opaque_square.png"))); CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE)); } SECTION("Paste image with semi transparent region") { - wxImage actual = background.Copy(); + wxImage actual("image/paste_input_background.png"); + REQUIRE(actual.IsOk()); + + const wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png"); + REQUIRE(transparent_square.IsOk()); + actual.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); CHECK_THAT(actual, RGBSameAs(wxImage("image/paste_result_background_plus_overlay_transparent_border_semitransparent_square.png"))); CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE)); } SECTION("Paste two semi transparent images on top of background") { - wxImage actual = background.Copy(); + wxImage actual("image/paste_input_background.png"); + REQUIRE(actual.IsOk()); + + const wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png"); + REQUIRE(transparent_square.IsOk()); + + const wxImage transparent_circle("image/paste_input_overlay_transparent_border_semitransparent_circle.png"); + REQUIRE(transparent_circle.IsOk()); + actual.Paste(transparent_circle, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); actual.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); CHECK_THAT(actual, RGBSimilarTo(wxImage("image/paste_result_background_plus_circle_plus_square.png"), 1)); @@ -1749,8 +1806,16 @@ TEST_CASE("wxImage::Paste", "[image][paste]") } SECTION("Paste two semi transparent images together first, then on top of background") { + wxImage actual("image/paste_input_background.png"); + REQUIRE(actual.IsOk()); + + const wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png"); + REQUIRE(transparent_square.IsOk()); + + const wxImage transparent_circle("image/paste_input_overlay_transparent_border_semitransparent_circle.png"); + REQUIRE(transparent_circle.IsOk()); + wxImage circle = transparent_circle.Copy(); - wxImage actual = background.Copy(); circle.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); actual.Paste(circle, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); // When applied in this order, two times a rounding difference is triggered. @@ -1759,6 +1824,12 @@ TEST_CASE("wxImage::Paste", "[image][paste]") } SECTION("Paste semitransparent image over transparent image") { + const wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png"); + REQUIRE(transparent_square.IsOk()); + + const wxImage transparent_circle("image/paste_input_overlay_transparent_border_semitransparent_circle.png"); + REQUIRE(transparent_circle.IsOk()); + wxImage actual(transparent_circle.GetSize()); actual.InitAlpha(); memset(actual.GetAlpha(), 0, actual.GetWidth() * actual.GetHeight()); @@ -1770,28 +1841,6 @@ TEST_CASE("wxImage::Paste", "[image][paste]") } SECTION("Paste fully transparent (masked) image over light image") // todo make test case for 'blend with mask' { - const static char* transparent_image_xpm[] = - { - "5 5 2 1", - " c None", // Mask - "y c #FFFF00", - " ", - " ", - " ", - " ", - " ", - }; - const static char* light_image_xpm[] = - { - "5 5 2 1", - " c None", - "y c #FFFF00", - "yyyyy", - "yyyyy", - "yyyyy", - "yyyyy", - "yyyyy", - }; wxImage actual(light_image_xpm); actual.InitAlpha(); wxImage paste(transparent_image_xpm); @@ -1801,28 +1850,6 @@ TEST_CASE("wxImage::Paste", "[image][paste]") } SECTION("Paste fully black (masked) image over light image") // todo make test case for 'blend with mask' { - const static char* black_image_xpm[] = - { - "5 5 2 1", - " c #000000", - "y c None", // Mask - " ", - " ", - " ", - " ", - " ", - }; - const static char* light_image_xpm[] = - { - "5 5 2 1", - " c None", - "y c #FFFF00", - "yyyyy", - "yyyyy", - "yyyyy", - "yyyyy", - "yyyyy", - }; wxImage actual(light_image_xpm); actual.InitAlpha(); wxImage paste(black_image_xpm); From 728f2f958f569db869bdc82a57016961703168ca Mon Sep 17 00:00:00 2001 From: Hartwig Date: Mon, 5 Oct 2020 18:17:16 +0200 Subject: [PATCH 087/105] Fix crash in wxImage::Paste() when using images without alpha Check for the presence of alpha channel before using it in the fallback code. Also add a unit test exercising this branch of the code and which crashed before. --- src/common/image.cpp | 7 ++++--- tests/image/image.cpp | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/common/image.cpp b/src/common/image.cpp index c62d0a909f..d6febece49 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -1786,13 +1786,14 @@ wxImage::Paste(const wxImage & image, int x, int y, { // Copy the non masked pixel memcpy(target_data + i, source_data + i, 3); - // Make the copied pixel fully opaque - alpha_target_data[i / 3] = wxALPHA_OPAQUE; + if (alpha_target_data != NULL) // Make the copied pixel fully opaque + alpha_target_data[i / 3] = wxALPHA_OPAQUE; } } source_data += source_step; target_data += target_step; - alpha_target_data += target_alpha_step; + if (alpha_target_data != NULL) + alpha_target_data += target_alpha_step; } } } diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 60248f0f76..c825a445a4 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -1540,6 +1540,10 @@ TEST_CASE("wxImage::Paste", "[image][paste]") wxImage expected(toggle_equal_size_xpm); actual.Paste(paste, 0, 0); CHECK_THAT(actual, RGBSameAs(expected)); + + // Without alpha using "compose" doesn't change anything. + actual.Paste(paste, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE); + CHECK_THAT(actual, RGBSameAs(expected)); } SECTION("Paste larger image") From 1668b0bb4eb6576c227668f6b7289c1f94c507e0 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 6 Oct 2020 02:14:27 +0200 Subject: [PATCH 088/105] Replace hard TABs in wx-config with spaces No real changes, just de-TAB-ify. --- wx-config.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wx-config.in b/wx-config.in index 16013d35b9..441f88ce92 100755 --- a/wx-config.in +++ b/wx-config.in @@ -1311,12 +1311,12 @@ if [ -n "$output_option_libs" ]; then _ldflags="-L$libdir" if [ -n "$MAC_FRAMEWORK" ]; then - wx_libs="-framework $MAC_FRAMEWORK" - if [ -n "$MAC_FRAMEWORK_PREFIX" ]; then - _ldflags="-F$MAC_FRAMEWORK_PREFIX" - else - _ldflags="" - fi + wx_libs="-framework $MAC_FRAMEWORK" + if [ -n "$MAC_FRAMEWORK_PREFIX" ]; then + _ldflags="-F$MAC_FRAMEWORK_PREFIX" + else + _ldflags="" + fi fi is_installed || [ -n "$flag_option_no_rpath" ] || _rpath="@WXCONFIG_RPATH@" From 96eb09a38389bb99376183048b51622f849b5c11 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 6 Oct 2020 02:14:46 +0200 Subject: [PATCH 089/105] Really ignore TABs in makefiles etc in the whitespace check Add missing ":" in the beginning of Git pathspecs to make the exclusions really work. Also add entries for Makefile.in, which is not caught by **/*akefile*, and other files in the root directory containing hard TABs. --- .github/workflows/code_checks.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/code_checks.yml b/.github/workflows/code_checks.yml index 85191fa9c4..fc46f8354c 100644 --- a/.github/workflows/code_checks.yml +++ b/.github/workflows/code_checks.yml @@ -55,8 +55,14 @@ jobs: run: | git fetch --depth=1 origin master git -c core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol,tab-in-indent \ - diff --check origin/master '*' \ - '!**/*akefile*' \ - '!**/*.sln' \ - '!**/*.vcproj' \ - '!**/*.xpm' + diff --check origin/master \ + ':!Makefile.in' \ + ':!config.guess' \ + ':!config.sub' \ + ':!configure' \ + ':!descrip.mms' \ + ':!install-sh' \ + ':!**/*akefile*' \ + ':!**/*.sln' \ + ':!**/*.vcproj' \ + ':!**/*.xpm' From 3e88df56f5afa2d0de4c4a563788f8476d749eb8 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Tue, 6 Oct 2020 18:22:39 +0200 Subject: [PATCH 090/105] Get rid of unused wxTransformMatrix As it is stated in matrix.cpp wxTransformMatrix was intended to be used in wxDC to replace the basic system of scaling/translation but actually it was never used. Because applying affine transformations can be done with wxAffineMatrix2D and wxDC::SetTransformMatrix() we can get rid of this dead code. Closes #13114. --- Makefile.in | 21 - build/bakefiles/files.bkl | 2 - build/cmake/files.cmake | 2 - build/files | 2 - build/msw/makefile.bcc | 28 - build/msw/makefile.gcc | 28 - build/msw/makefile.vc | 28 - build/msw/wx_core.vcxproj | 2 - build/msw/wx_core.vcxproj.filters | 6 - build/msw/wx_vc7_core.vcproj | 6 - build/msw/wx_vc8_core.vcproj | 8 - build/msw/wx_vc9_core.vcproj | 8 - build/osx/wxcocoa.xcodeproj/project.pbxproj | 8 - build/osx/wxiphone.xcodeproj/project.pbxproj | 4 - include/wx/matrix.h | 234 -------- src/common/matrix.cpp | 600 ------------------- tests/allheaders.h | 1 - 17 files changed, 988 deletions(-) delete mode 100644 include/wx/matrix.h delete mode 100644 src/common/matrix.cpp diff --git a/Makefile.in b/Makefile.in index 62beaa8482..83f5f3489d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -3879,7 +3879,6 @@ COND_USE_GUI_1_ALL_GUI_HEADERS = \ wx/listbase.h \ wx/listbook.h \ wx/listctrl.h \ - wx/matrix.h \ wx/menuitem.h \ wx/metafile.h \ wx/minifram.h \ @@ -4516,7 +4515,6 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS = \ monodll_lboxcmn.o \ monodll_listctrlcmn.o \ monodll_markupparser.o \ - monodll_matrix.o \ monodll_menucmn.o \ monodll_modalhook.o \ monodll_mousemanager.o \ @@ -4777,7 +4775,6 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS = \ monodll_lboxcmn.o \ monodll_listctrlcmn.o \ monodll_markupparser.o \ - monodll_matrix.o \ monodll_menucmn.o \ monodll_modalhook.o \ monodll_mousemanager.o \ @@ -6503,7 +6500,6 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS_1 = \ monolib_lboxcmn.o \ monolib_listctrlcmn.o \ monolib_markupparser.o \ - monolib_matrix.o \ monolib_menucmn.o \ monolib_modalhook.o \ monolib_mousemanager.o \ @@ -6764,7 +6760,6 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS_1 = \ monolib_lboxcmn.o \ monolib_listctrlcmn.o \ monolib_markupparser.o \ - monolib_matrix.o \ monolib_menucmn.o \ monolib_modalhook.o \ monolib_mousemanager.o \ @@ -8636,7 +8631,6 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS_2 = \ coredll_lboxcmn.o \ coredll_listctrlcmn.o \ coredll_markupparser.o \ - coredll_matrix.o \ coredll_menucmn.o \ coredll_modalhook.o \ coredll_mousemanager.o \ @@ -8897,7 +8891,6 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS_2 = \ coredll_lboxcmn.o \ coredll_listctrlcmn.o \ coredll_markupparser.o \ - coredll_matrix.o \ coredll_menucmn.o \ coredll_modalhook.o \ coredll_mousemanager.o \ @@ -10359,7 +10352,6 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS_3 = \ corelib_lboxcmn.o \ corelib_listctrlcmn.o \ corelib_markupparser.o \ - corelib_matrix.o \ corelib_menucmn.o \ corelib_modalhook.o \ corelib_mousemanager.o \ @@ -10620,7 +10612,6 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS_3 = \ corelib_lboxcmn.o \ corelib_listctrlcmn.o \ corelib_markupparser.o \ - corelib_matrix.o \ corelib_menucmn.o \ corelib_modalhook.o \ corelib_mousemanager.o \ @@ -20472,9 +20463,6 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP) @COND_USE_GUI_1@monodll_markupparser.o: $(srcdir)/src/common/markupparser.cpp $(MONODLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/markupparser.cpp -@COND_USE_GUI_1@monodll_matrix.o: $(srcdir)/src/common/matrix.cpp $(MONODLL_ODEP) -@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/matrix.cpp - @COND_USE_GUI_1@monodll_menucmn.o: $(srcdir)/src/common/menucmn.cpp $(MONODLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/menucmn.cpp @@ -25740,9 +25728,6 @@ monolib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1@monolib_markupparser.o: $(srcdir)/src/common/markupparser.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/markupparser.cpp -@COND_USE_GUI_1@monolib_matrix.o: $(srcdir)/src/common/matrix.cpp $(MONOLIB_ODEP) -@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/matrix.cpp - @COND_USE_GUI_1@monolib_menucmn.o: $(srcdir)/src/common/menucmn.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/menucmn.cpp @@ -31089,9 +31074,6 @@ coredll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(COREDLL_ODEP) @COND_USE_GUI_1@coredll_markupparser.o: $(srcdir)/src/common/markupparser.cpp $(COREDLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/common/markupparser.cpp -@COND_USE_GUI_1@coredll_matrix.o: $(srcdir)/src/common/matrix.cpp $(COREDLL_ODEP) -@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/common/matrix.cpp - @COND_USE_GUI_1@coredll_menucmn.o: $(srcdir)/src/common/menucmn.cpp $(COREDLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/common/menucmn.cpp @@ -35346,9 +35328,6 @@ corelib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(CORELIB_ODEP) @COND_USE_GUI_1@corelib_markupparser.o: $(srcdir)/src/common/markupparser.cpp $(CORELIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/common/markupparser.cpp -@COND_USE_GUI_1@corelib_matrix.o: $(srcdir)/src/common/matrix.cpp $(CORELIB_ODEP) -@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/common/matrix.cpp - @COND_USE_GUI_1@corelib_menucmn.o: $(srcdir)/src/common/menucmn.cpp $(CORELIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/common/menucmn.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 6b906206a4..7752bbe117 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -883,7 +883,6 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/common/lboxcmn.cpp src/common/listctrlcmn.cpp src/common/markupparser.cpp - src/common/matrix.cpp src/common/menucmn.cpp src/common/modalhook.cpp src/common/mousemanager.cpp @@ -1188,7 +1187,6 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/listbase.h wx/listbook.h wx/listctrl.h - wx/matrix.h wx/menuitem.h wx/metafile.h wx/minifram.h diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index 8165d51792..3d76134938 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -787,7 +787,6 @@ set(GUI_CMN_SRC src/common/lboxcmn.cpp src/common/listctrlcmn.cpp src/common/markupparser.cpp - src/common/matrix.cpp src/common/menucmn.cpp src/common/modalhook.cpp src/common/mousemanager.cpp @@ -1097,7 +1096,6 @@ set(GUI_CMN_HDR wx/listbase.h wx/listbook.h wx/listctrl.h - wx/matrix.h wx/menuitem.h wx/metafile.h wx/minifram.h diff --git a/build/files b/build/files index 39a49b19c6..cf9a6341c1 100644 --- a/build/files +++ b/build/files @@ -806,7 +806,6 @@ GUI_CMN_SRC = src/common/lboxcmn.cpp src/common/listctrlcmn.cpp src/common/markupparser.cpp - src/common/matrix.cpp src/common/menucmn.cpp src/common/modalhook.cpp src/common/mousemanager.cpp @@ -1101,7 +1100,6 @@ GUI_CMN_HDR = wx/listbook.h wx/listbox.h wx/listctrl.h - wx/matrix.h wx/mdi.h wx/menu.h wx/menuitem.h diff --git a/build/msw/makefile.bcc b/build/msw/makefile.bcc index 1ca436dce3..fb0f397081 100644 --- a/build/msw/makefile.bcc +++ b/build/msw/makefile.bcc @@ -2028,7 +2028,6 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.obj \ $(OBJS)\monodll_listctrlcmn.obj \ $(OBJS)\monodll_markupparser.obj \ - $(OBJS)\monodll_matrix.obj \ $(OBJS)\monodll_menucmn.obj \ $(OBJS)\monodll_modalhook.obj \ $(OBJS)\monodll_mousemanager.obj \ @@ -2355,7 +2354,6 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.obj \ $(OBJS)\monodll_listctrlcmn.obj \ $(OBJS)\monodll_markupparser.obj \ - $(OBJS)\monodll_matrix.obj \ $(OBJS)\monodll_menucmn.obj \ $(OBJS)\monodll_modalhook.obj \ $(OBJS)\monodll_mousemanager.obj \ @@ -2862,7 +2860,6 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.obj \ $(OBJS)\monolib_listctrlcmn.obj \ $(OBJS)\monolib_markupparser.obj \ - $(OBJS)\monolib_matrix.obj \ $(OBJS)\monolib_menucmn.obj \ $(OBJS)\monolib_modalhook.obj \ $(OBJS)\monolib_mousemanager.obj \ @@ -3189,7 +3186,6 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.obj \ $(OBJS)\monolib_listctrlcmn.obj \ $(OBJS)\monolib_markupparser.obj \ - $(OBJS)\monolib_matrix.obj \ $(OBJS)\monolib_menucmn.obj \ $(OBJS)\monolib_modalhook.obj \ $(OBJS)\monolib_mousemanager.obj \ @@ -3569,7 +3565,6 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.obj \ $(OBJS)\coredll_listctrlcmn.obj \ $(OBJS)\coredll_markupparser.obj \ - $(OBJS)\coredll_matrix.obj \ $(OBJS)\coredll_menucmn.obj \ $(OBJS)\coredll_modalhook.obj \ $(OBJS)\coredll_mousemanager.obj \ @@ -3896,7 +3891,6 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.obj \ $(OBJS)\coredll_listctrlcmn.obj \ $(OBJS)\coredll_markupparser.obj \ - $(OBJS)\coredll_matrix.obj \ $(OBJS)\coredll_menucmn.obj \ $(OBJS)\coredll_modalhook.obj \ $(OBJS)\coredll_mousemanager.obj \ @@ -4242,7 +4236,6 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.obj \ $(OBJS)\corelib_listctrlcmn.obj \ $(OBJS)\corelib_markupparser.obj \ - $(OBJS)\corelib_matrix.obj \ $(OBJS)\corelib_menucmn.obj \ $(OBJS)\corelib_modalhook.obj \ $(OBJS)\corelib_mousemanager.obj \ @@ -4569,7 +4562,6 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.obj \ $(OBJS)\corelib_listctrlcmn.obj \ $(OBJS)\corelib_markupparser.obj \ - $(OBJS)\corelib_matrix.obj \ $(OBJS)\corelib_menucmn.obj \ $(OBJS)\corelib_modalhook.obj \ $(OBJS)\corelib_mousemanager.obj \ @@ -8403,11 +8395,6 @@ $(OBJS)\monodll_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif -!if "$(USE_GUI)" == "1" -$(OBJS)\monodll_matrix.obj: ..\..\src\common\matrix.cpp - $(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\common\matrix.cpp -!endif - !if "$(USE_GUI)" == "1" $(OBJS)\monodll_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -10957,11 +10944,6 @@ $(OBJS)\monolib_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif -!if "$(USE_GUI)" == "1" -$(OBJS)\monolib_matrix.obj: ..\..\src\common\matrix.cpp - $(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\matrix.cpp -!endif - !if "$(USE_GUI)" == "1" $(OBJS)\monolib_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -13469,11 +13451,6 @@ $(OBJS)\coredll_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif -!if "$(USE_GUI)" == "1" -$(OBJS)\coredll_matrix.obj: ..\..\src\common\matrix.cpp - $(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\common\matrix.cpp -!endif - !if "$(USE_GUI)" == "1" $(OBJS)\coredll_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -15204,11 +15181,6 @@ $(OBJS)\corelib_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif -!if "$(USE_GUI)" == "1" -$(OBJS)\corelib_matrix.obj: ..\..\src\common\matrix.cpp - $(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\common\matrix.cpp -!endif - !if "$(USE_GUI)" == "1" $(OBJS)\corelib_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\common\menucmn.cpp diff --git a/build/msw/makefile.gcc b/build/msw/makefile.gcc index a5488e00a1..bda89b0f3b 100644 --- a/build/msw/makefile.gcc +++ b/build/msw/makefile.gcc @@ -2053,7 +2053,6 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.o \ $(OBJS)\monodll_listctrlcmn.o \ $(OBJS)\monodll_markupparser.o \ - $(OBJS)\monodll_matrix.o \ $(OBJS)\monodll_menucmn.o \ $(OBJS)\monodll_modalhook.o \ $(OBJS)\monodll_mousemanager.o \ @@ -2382,7 +2381,6 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.o \ $(OBJS)\monodll_listctrlcmn.o \ $(OBJS)\monodll_markupparser.o \ - $(OBJS)\monodll_matrix.o \ $(OBJS)\monodll_menucmn.o \ $(OBJS)\monodll_modalhook.o \ $(OBJS)\monodll_mousemanager.o \ @@ -2893,7 +2891,6 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.o \ $(OBJS)\monolib_listctrlcmn.o \ $(OBJS)\monolib_markupparser.o \ - $(OBJS)\monolib_matrix.o \ $(OBJS)\monolib_menucmn.o \ $(OBJS)\monolib_modalhook.o \ $(OBJS)\monolib_mousemanager.o \ @@ -3222,7 +3219,6 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.o \ $(OBJS)\monolib_listctrlcmn.o \ $(OBJS)\monolib_markupparser.o \ - $(OBJS)\monolib_matrix.o \ $(OBJS)\monolib_menucmn.o \ $(OBJS)\monolib_modalhook.o \ $(OBJS)\monolib_mousemanager.o \ @@ -3616,7 +3612,6 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.o \ $(OBJS)\coredll_listctrlcmn.o \ $(OBJS)\coredll_markupparser.o \ - $(OBJS)\coredll_matrix.o \ $(OBJS)\coredll_menucmn.o \ $(OBJS)\coredll_modalhook.o \ $(OBJS)\coredll_mousemanager.o \ @@ -3945,7 +3940,6 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.o \ $(OBJS)\coredll_listctrlcmn.o \ $(OBJS)\coredll_markupparser.o \ - $(OBJS)\coredll_matrix.o \ $(OBJS)\coredll_menucmn.o \ $(OBJS)\coredll_modalhook.o \ $(OBJS)\coredll_mousemanager.o \ @@ -4297,7 +4291,6 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.o \ $(OBJS)\corelib_listctrlcmn.o \ $(OBJS)\corelib_markupparser.o \ - $(OBJS)\corelib_matrix.o \ $(OBJS)\corelib_menucmn.o \ $(OBJS)\corelib_modalhook.o \ $(OBJS)\corelib_mousemanager.o \ @@ -4626,7 +4619,6 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.o \ $(OBJS)\corelib_listctrlcmn.o \ $(OBJS)\corelib_markupparser.o \ - $(OBJS)\corelib_matrix.o \ $(OBJS)\corelib_menucmn.o \ $(OBJS)\corelib_modalhook.o \ $(OBJS)\corelib_mousemanager.o \ @@ -8707,11 +8699,6 @@ $(OBJS)\monodll_markupparser.o: ../../src/common/markupparser.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< endif -ifeq ($(USE_GUI),1) -$(OBJS)\monodll_matrix.o: ../../src/common/matrix.cpp - $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< -endif - ifeq ($(USE_GUI),1) $(OBJS)\monodll_menucmn.o: ../../src/common/menucmn.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< @@ -11261,11 +11248,6 @@ $(OBJS)\monolib_markupparser.o: ../../src/common/markupparser.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< endif -ifeq ($(USE_GUI),1) -$(OBJS)\monolib_matrix.o: ../../src/common/matrix.cpp - $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< -endif - ifeq ($(USE_GUI),1) $(OBJS)\monolib_menucmn.o: ../../src/common/menucmn.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< @@ -13773,11 +13755,6 @@ $(OBJS)\coredll_markupparser.o: ../../src/common/markupparser.cpp $(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $< endif -ifeq ($(USE_GUI),1) -$(OBJS)\coredll_matrix.o: ../../src/common/matrix.cpp - $(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $< -endif - ifeq ($(USE_GUI),1) $(OBJS)\coredll_menucmn.o: ../../src/common/menucmn.cpp $(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $< @@ -15508,11 +15485,6 @@ $(OBJS)\corelib_markupparser.o: ../../src/common/markupparser.cpp $(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $< endif -ifeq ($(USE_GUI),1) -$(OBJS)\corelib_matrix.o: ../../src/common/matrix.cpp - $(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $< -endif - ifeq ($(USE_GUI),1) $(OBJS)\corelib_menucmn.o: ../../src/common/menucmn.cpp $(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $< diff --git a/build/msw/makefile.vc b/build/msw/makefile.vc index 2852105611..72bc753c29 100644 --- a/build/msw/makefile.vc +++ b/build/msw/makefile.vc @@ -2365,7 +2365,6 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.obj \ $(OBJS)\monodll_listctrlcmn.obj \ $(OBJS)\monodll_markupparser.obj \ - $(OBJS)\monodll_matrix.obj \ $(OBJS)\monodll_menucmn.obj \ $(OBJS)\monodll_modalhook.obj \ $(OBJS)\monodll_mousemanager.obj \ @@ -2692,7 +2691,6 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.obj \ $(OBJS)\monodll_listctrlcmn.obj \ $(OBJS)\monodll_markupparser.obj \ - $(OBJS)\monodll_matrix.obj \ $(OBJS)\monodll_menucmn.obj \ $(OBJS)\monodll_modalhook.obj \ $(OBJS)\monodll_mousemanager.obj \ @@ -3205,7 +3203,6 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.obj \ $(OBJS)\monolib_listctrlcmn.obj \ $(OBJS)\monolib_markupparser.obj \ - $(OBJS)\monolib_matrix.obj \ $(OBJS)\monolib_menucmn.obj \ $(OBJS)\monolib_modalhook.obj \ $(OBJS)\monolib_mousemanager.obj \ @@ -3532,7 +3529,6 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.obj \ $(OBJS)\monolib_listctrlcmn.obj \ $(OBJS)\monolib_markupparser.obj \ - $(OBJS)\monolib_matrix.obj \ $(OBJS)\monolib_menucmn.obj \ $(OBJS)\monolib_modalhook.obj \ $(OBJS)\monolib_mousemanager.obj \ @@ -3978,7 +3974,6 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.obj \ $(OBJS)\coredll_listctrlcmn.obj \ $(OBJS)\coredll_markupparser.obj \ - $(OBJS)\coredll_matrix.obj \ $(OBJS)\coredll_menucmn.obj \ $(OBJS)\coredll_modalhook.obj \ $(OBJS)\coredll_mousemanager.obj \ @@ -4305,7 +4300,6 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.obj \ $(OBJS)\coredll_listctrlcmn.obj \ $(OBJS)\coredll_markupparser.obj \ - $(OBJS)\coredll_matrix.obj \ $(OBJS)\coredll_menucmn.obj \ $(OBJS)\coredll_modalhook.obj \ $(OBJS)\coredll_mousemanager.obj \ @@ -4657,7 +4651,6 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.obj \ $(OBJS)\corelib_listctrlcmn.obj \ $(OBJS)\corelib_markupparser.obj \ - $(OBJS)\corelib_matrix.obj \ $(OBJS)\corelib_menucmn.obj \ $(OBJS)\corelib_modalhook.obj \ $(OBJS)\corelib_mousemanager.obj \ @@ -4984,7 +4977,6 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.obj \ $(OBJS)\corelib_listctrlcmn.obj \ $(OBJS)\corelib_markupparser.obj \ - $(OBJS)\corelib_matrix.obj \ $(OBJS)\corelib_menucmn.obj \ $(OBJS)\corelib_modalhook.obj \ $(OBJS)\corelib_mousemanager.obj \ @@ -9138,11 +9130,6 @@ $(OBJS)\monodll_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif -!if "$(USE_GUI)" == "1" -$(OBJS)\monodll_matrix.obj: ..\..\src\common\matrix.cpp - $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\matrix.cpp -!endif - !if "$(USE_GUI)" == "1" $(OBJS)\monodll_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -11692,11 +11679,6 @@ $(OBJS)\monolib_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif -!if "$(USE_GUI)" == "1" -$(OBJS)\monolib_matrix.obj: ..\..\src\common\matrix.cpp - $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\matrix.cpp -!endif - !if "$(USE_GUI)" == "1" $(OBJS)\monolib_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -14204,11 +14186,6 @@ $(OBJS)\coredll_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif -!if "$(USE_GUI)" == "1" -$(OBJS)\coredll_matrix.obj: ..\..\src\common\matrix.cpp - $(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\common\matrix.cpp -!endif - !if "$(USE_GUI)" == "1" $(OBJS)\coredll_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -15939,11 +15916,6 @@ $(OBJS)\corelib_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif -!if "$(USE_GUI)" == "1" -$(OBJS)\corelib_matrix.obj: ..\..\src\common\matrix.cpp - $(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\common\matrix.cpp -!endif - !if "$(USE_GUI)" == "1" $(OBJS)\corelib_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\common\menucmn.cpp diff --git a/build/msw/wx_core.vcxproj b/build/msw/wx_core.vcxproj index 8089f36d7b..2d84caa37c 100644 --- a/build/msw/wx_core.vcxproj +++ b/build/msw/wx_core.vcxproj @@ -541,7 +541,6 @@ - @@ -1338,7 +1337,6 @@ - diff --git a/build/msw/wx_core.vcxproj.filters b/build/msw/wx_core.vcxproj.filters index 83c265118a..57bc68602c 100644 --- a/build/msw/wx_core.vcxproj.filters +++ b/build/msw/wx_core.vcxproj.filters @@ -294,9 +294,6 @@ Common Sources - - Common Sources - Common Sources @@ -1618,9 +1615,6 @@ Common Headers - - Common Headers - Common Headers diff --git a/build/msw/wx_vc7_core.vcproj b/build/msw/wx_vc7_core.vcproj index ad378068ce..ef9520b43f 100644 --- a/build/msw/wx_vc7_core.vcproj +++ b/build/msw/wx_vc7_core.vcproj @@ -567,9 +567,6 @@ - - @@ -2477,9 +2474,6 @@ - - diff --git a/build/msw/wx_vc8_core.vcproj b/build/msw/wx_vc8_core.vcproj index e956ab6df8..a25ffbdd55 100644 --- a/build/msw/wx_vc8_core.vcproj +++ b/build/msw/wx_vc8_core.vcproj @@ -1161,10 +1161,6 @@ RelativePath="..\..\src\common\markupparser.cpp" > - - @@ -3804,10 +3800,6 @@ RelativePath="..\..\include\wx\propgrid\manager.h" > - - diff --git a/build/msw/wx_vc9_core.vcproj b/build/msw/wx_vc9_core.vcproj index a6d3ec7b1d..f8d4cc4439 100644 --- a/build/msw/wx_vc9_core.vcproj +++ b/build/msw/wx_vc9_core.vcproj @@ -1157,10 +1157,6 @@ RelativePath="..\..\src\common\markupparser.cpp" > - - @@ -3800,10 +3796,6 @@ RelativePath="..\..\include\wx\propgrid\manager.h" > - - diff --git a/build/osx/wxcocoa.xcodeproj/project.pbxproj b/build/osx/wxcocoa.xcodeproj/project.pbxproj index 5ce91d315a..771d6ce9fe 100644 --- a/build/osx/wxcocoa.xcodeproj/project.pbxproj +++ b/build/osx/wxcocoa.xcodeproj/project.pbxproj @@ -1766,9 +1766,6 @@ 9A178ED42D96329D8CBF9B89 /* tif_predict.c in Sources */ = {isa = PBXBuildFile; fileRef = 2FA01C426EAF38D3B9ED35AC /* tif_predict.c */; }; 9A178ED42D96329D8CBF9B8A /* tif_predict.c in Sources */ = {isa = PBXBuildFile; fileRef = 2FA01C426EAF38D3B9ED35AC /* tif_predict.c */; }; 9A178ED42D96329D8CBF9B8B /* tif_predict.c in Sources */ = {isa = PBXBuildFile; fileRef = 2FA01C426EAF38D3B9ED35AC /* tif_predict.c */; }; - 9A83D365AD1F37FA9C7030C2 /* matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF330EAACFA53877BE289896 /* matrix.cpp */; }; - 9A83D365AD1F37FA9C7030C3 /* matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF330EAACFA53877BE289896 /* matrix.cpp */; }; - 9A83D365AD1F37FA9C7030C4 /* matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF330EAACFA53877BE289896 /* matrix.cpp */; }; 9B3F9D04FB533D99B58BD519 /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 029486D6A2EC3DE0902A6A24 /* jfdctfst.c */; }; 9B3F9D04FB533D99B58BD51A /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 029486D6A2EC3DE0902A6A24 /* jfdctfst.c */; }; 9B3F9D04FB533D99B58BD51B /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 029486D6A2EC3DE0902A6A24 /* jfdctfst.c */; }; @@ -4757,7 +4754,6 @@ EEADAA811BBF3CBBB9E254FD /* xh_split.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_split.cpp; path = ../../src/xrc/xh_split.cpp; sourceTree = ""; }; EED7C691150139EFA35E8EBD /* utils_osx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = utils_osx.cpp; path = ../../src/osx/utils_osx.cpp; sourceTree = ""; }; EEE82083BFA430D5B58F8A04 /* regfree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regfree.c; path = ../../src/regex/regfree.c; sourceTree = ""; }; - EF330EAACFA53877BE289896 /* matrix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = matrix.cpp; path = ../../src/common/matrix.cpp; sourceTree = ""; }; F01DDE448E4C3983ACCE67FD /* appcmn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = appcmn.cpp; path = ../../src/common/appcmn.cpp; sourceTree = ""; }; F0905A1EBD653F6D82395602 /* xh_combo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_combo.cpp; path = ../../src/xrc/xh_combo.cpp; sourceTree = ""; }; F175D6E8E5723FC797701275 /* menucmn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = menucmn.cpp; path = ../../src/common/menucmn.cpp; sourceTree = ""; }; @@ -5533,7 +5529,6 @@ 9660AE8FEB7B3EDB857B9238 /* lboxcmn.cpp */, E1B1FBB2BCC43BA7A45E9438 /* listctrlcmn.cpp */, DA7F7633279936EFA0B9C5CF /* markupparser.cpp */, - EF330EAACFA53877BE289896 /* matrix.cpp */, F175D6E8E5723FC797701275 /* menucmn.cpp */, 58E7C516E2453A269280A404 /* modalhook.cpp */, D037EA567C253DEEA17E822B /* mousemanager.cpp */, @@ -7748,7 +7743,6 @@ CFF73578F04D357E83D1D832 /* lboxcmn.cpp in Sources */, 164010B26D363F5FA09785B8 /* listctrlcmn.cpp in Sources */, 2F7F5B9BBCD83D90B237A1A2 /* markupparser.cpp in Sources */, - 9A83D365AD1F37FA9C7030C4 /* matrix.cpp in Sources */, E3A4615870B139D29FE727C3 /* menucmn.cpp in Sources */, 171F09F8DD553FA5B4B3FAE4 /* modalhook.cpp in Sources */, BD49EC50CB363642BDBF25CA /* mousemanager.cpp in Sources */, @@ -8426,7 +8420,6 @@ CFF73578F04D357E83D1D831 /* lboxcmn.cpp in Sources */, 164010B26D363F5FA09785B7 /* listctrlcmn.cpp in Sources */, 2F7F5B9BBCD83D90B237A1A1 /* markupparser.cpp in Sources */, - 9A83D365AD1F37FA9C7030C3 /* matrix.cpp in Sources */, E3A4615870B139D29FE727C2 /* menucmn.cpp in Sources */, 171F09F8DD553FA5B4B3FAE3 /* modalhook.cpp in Sources */, BD49EC50CB363642BDBF25C9 /* mousemanager.cpp in Sources */, @@ -9657,7 +9650,6 @@ CFF73578F04D357E83D1D830 /* lboxcmn.cpp in Sources */, 164010B26D363F5FA09785B6 /* listctrlcmn.cpp in Sources */, 2F7F5B9BBCD83D90B237A1A0 /* markupparser.cpp in Sources */, - 9A83D365AD1F37FA9C7030C2 /* matrix.cpp in Sources */, E3A4615870B139D29FE727C1 /* menucmn.cpp in Sources */, 171F09F8DD553FA5B4B3FAE2 /* modalhook.cpp in Sources */, BD49EC50CB363642BDBF25C8 /* mousemanager.cpp in Sources */, diff --git a/build/osx/wxiphone.xcodeproj/project.pbxproj b/build/osx/wxiphone.xcodeproj/project.pbxproj index 5f78a8530d..c13eba02f4 100644 --- a/build/osx/wxiphone.xcodeproj/project.pbxproj +++ b/build/osx/wxiphone.xcodeproj/project.pbxproj @@ -514,7 +514,6 @@ 99E7A46106C03484BA70D29E /* tif_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 5D2F8259CC99380CB8217DEF /* tif_unix.c */; }; 99F7D7BFBB543A04AB728375 /* m_hline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECA4A44BEC2F3AED8CF0C911 /* m_hline.cpp */; }; 9A178ED42D96329D8CBF9B89 /* tif_predict.c in Sources */ = {isa = PBXBuildFile; fileRef = 2FA01C426EAF38D3B9ED35AC /* tif_predict.c */; }; - 9A83D365AD1F37FA9C7030C2 /* matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF330EAACFA53877BE289896 /* matrix.cpp */; }; 9B3F9D04FB533D99B58BD519 /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 029486D6A2EC3DE0902A6A24 /* jfdctfst.c */; }; 9B6A35E706543CDAA6A5014A /* LexGui4Cli.cxx in Sources */ = {isa = PBXBuildFile; fileRef = FFB767BD2C7235F293F45796 /* LexGui4Cli.cxx */; }; 9B8E5690A6103FC1BDC6C47E /* pngread.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D6506AEA5A323B8735F126 /* pngread.c */; }; @@ -1664,7 +1663,6 @@ EEADAA811BBF3CBBB9E254FD /* xh_split.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_split.cpp; path = ../../src/xrc/xh_split.cpp; sourceTree = ""; }; EED7C691150139EFA35E8EBD /* utils_osx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = utils_osx.cpp; path = ../../src/osx/utils_osx.cpp; sourceTree = ""; }; EEE82083BFA430D5B58F8A04 /* regfree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regfree.c; path = ../../src/regex/regfree.c; sourceTree = ""; }; - EF330EAACFA53877BE289896 /* matrix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = matrix.cpp; path = ../../src/common/matrix.cpp; sourceTree = ""; }; F01DDE448E4C3983ACCE67FD /* appcmn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = appcmn.cpp; path = ../../src/common/appcmn.cpp; sourceTree = ""; }; F0905A1EBD653F6D82395602 /* xh_combo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_combo.cpp; path = ../../src/xrc/xh_combo.cpp; sourceTree = ""; }; F175D6E8E5723FC797701275 /* menucmn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = menucmn.cpp; path = ../../src/common/menucmn.cpp; sourceTree = ""; }; @@ -2121,7 +2119,6 @@ 9660AE8FEB7B3EDB857B9238 /* lboxcmn.cpp */, E1B1FBB2BCC43BA7A45E9438 /* listctrlcmn.cpp */, DA7F7633279936EFA0B9C5CF /* markupparser.cpp */, - EF330EAACFA53877BE289896 /* matrix.cpp */, F175D6E8E5723FC797701275 /* menucmn.cpp */, 58E7C516E2453A269280A404 /* modalhook.cpp */, D037EA567C253DEEA17E822B /* mousemanager.cpp */, @@ -3172,7 +3169,6 @@ CFF73578F04D357E83D1D830 /* lboxcmn.cpp in Sources */, 164010B26D363F5FA09785B6 /* listctrlcmn.cpp in Sources */, 2F7F5B9BBCD83D90B237A1A0 /* markupparser.cpp in Sources */, - 9A83D365AD1F37FA9C7030C2 /* matrix.cpp in Sources */, E3A4615870B139D29FE727C1 /* menucmn.cpp in Sources */, 171F09F8DD553FA5B4B3FAE2 /* modalhook.cpp in Sources */, BD49EC50CB363642BDBF25C8 /* mousemanager.cpp in Sources */, diff --git a/include/wx/matrix.h b/include/wx/matrix.h deleted file mode 100644 index b45473e3ee..0000000000 --- a/include/wx/matrix.h +++ /dev/null @@ -1,234 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: wx/matrix.h -// Purpose: wxTransformMatrix class. NOT YET USED -// Author: Chris Breeze, Julian Smart -// Modified by: Klaas Holwerda -// Created: 01/02/97 -// Copyright: (c) Julian Smart, Chris Breeze -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#ifndef _WX_MATRIXH__ -#define _WX_MATRIXH__ - -//! headerfiles="matrix.h wx/object.h" -#include "wx/object.h" -#include "wx/math.h" - -//! codefiles="matrix.cpp" - -// A simple 3x3 matrix. This may be replaced by a more general matrix -// class some day. -// -// Note: this is intended to be used in wxDC at some point to replace -// the current system of scaling/translation. It is not yet used. - -//:definition -// A 3x3 matrix to do 2D transformations. -// It can be used to map data to window coordinates, -// and also for manipulating your own data. -// For example drawing a picture (composed of several primitives) -// at a certain coordinate and angle within another parent picture. -// At all times m_isIdentity is set if the matrix itself is an Identity matrix. -// It is used where possible to optimize calculations. -class WXDLLIMPEXP_CORE wxTransformMatrix: public wxObject -{ -public: - wxTransformMatrix(); - wxTransformMatrix(const wxTransformMatrix& mat); - - //get the value in the matrix at col,row - //rows are horizontal (second index of m_matrix member) - //columns are vertical (first index of m_matrix member) - double GetValue(int col, int row) const; - - //set the value in the matrix at col,row - //rows are horizontal (second index of m_matrix member) - //columns are vertical (first index of m_matrix member) - void SetValue(int col, int row, double value); - - void operator = (const wxTransformMatrix& mat); - bool operator == (const wxTransformMatrix& mat) const; - bool operator != (const wxTransformMatrix& mat) const; - - //multiply every element by t - wxTransformMatrix& operator*=(const double& t); - //divide every element by t - wxTransformMatrix& operator/=(const double& t); - //add matrix m to this t - wxTransformMatrix& operator+=(const wxTransformMatrix& m); - //subtract matrix m from this - wxTransformMatrix& operator-=(const wxTransformMatrix& m); - //multiply matrix m with this - wxTransformMatrix& operator*=(const wxTransformMatrix& m); - - // constant operators - - //multiply every element by t and return result - wxTransformMatrix operator*(const double& t) const; - //divide this matrix by t and return result - wxTransformMatrix operator/(const double& t) const; - //add matrix m to this and return result - wxTransformMatrix operator+(const wxTransformMatrix& m) const; - //subtract matrix m from this and return result - wxTransformMatrix operator-(const wxTransformMatrix& m) const; - //multiply this by matrix m and return result - wxTransformMatrix operator*(const wxTransformMatrix& m) const; - wxTransformMatrix operator-() const; - - //rows are horizontal (second index of m_matrix member) - //columns are vertical (first index of m_matrix member) - double& operator()(int col, int row); - - //rows are horizontal (second index of m_matrix member) - //columns are vertical (first index of m_matrix member) - double operator()(int col, int row) const; - - // Invert matrix - bool Invert(); - - // Make into identity matrix - bool Identity(); - - // Is the matrix the identity matrix? - // Only returns a flag, which is set whenever an operation - // is done. - inline bool IsIdentity() const { return m_isIdentity; } - - // This does an actual check. - inline bool IsIdentity1() const ; - - //Scale by scale (isotropic scaling i.e. the same in x and y): - //!ex: - //!code: | scale 0 0 | - //!code: matrix' = | 0 scale 0 | x matrix - //!code: | 0 0 scale | - bool Scale(double scale); - - //Scale with center point and x/y scale - // - //!ex: - //!code: | xs 0 xc(1-xs) | - //!code: matrix' = | 0 ys yc(1-ys) | x matrix - //!code: | 0 0 1 | - wxTransformMatrix& Scale(const double &xs, const double &ys,const double &xc, const double &yc); - - // mirror a matrix in x, y - //!ex: - //!code: | -1 0 0 | - //!code: matrix' = | 0 -1 0 | x matrix - //!code: | 0 0 1 | - wxTransformMatrix& Mirror(bool x=true, bool y=false); - // Translate by dx, dy: - //!ex: - //!code: | 1 0 dx | - //!code: matrix' = | 0 1 dy | x matrix - //!code: | 0 0 1 | - bool Translate(double x, double y); - - // Rotate clockwise by the given number of degrees: - //!ex: - //!code: | cos sin 0 | - //!code: matrix' = | -sin cos 0 | x matrix - //!code: | 0 0 1 | - bool Rotate(double angle); - - //Rotate counter clockwise with point of rotation - // - //!ex: - //!code: | cos(r) -sin(r) x(1-cos(r))+y(sin(r)| - //!code: matrix' = | sin(r) cos(r) y(1-cos(r))-x(sin(r)| x matrix - //!code: | 0 0 1 | - wxTransformMatrix& Rotate(const double &r, const double &x, const double &y); - - // Transform X value from logical to device - inline double TransformX(double x) const; - - // Transform Y value from logical to device - inline double TransformY(double y) const; - - // Transform a point from logical to device coordinates - bool TransformPoint(double x, double y, double& tx, double& ty) const; - - // Transform a point from device to logical coordinates. - // Example of use: - // wxTransformMatrix mat = dc.GetTransformation(); - // mat.Invert(); - // mat.InverseTransformPoint(x, y, x1, y1); - // OR (shorthand:) - // dc.LogicalToDevice(x, y, x1, y1); - // The latter is slightly less efficient if we're doing several - // conversions, since the matrix is inverted several times. - // N.B. 'this' matrix is the inverse at this point - bool InverseTransformPoint(double x, double y, double& tx, double& ty) const; - - double Get_scaleX(); - double Get_scaleY(); - double GetRotation(); - void SetRotation(double rotation); - - -public: - double m_matrix[3][3]; - bool m_isIdentity; -}; - - -/* -Chris Breeze reported, that -some functions of wxTransformMatrix cannot work because it is not -known if he matrix has been inverted. Be careful when using it. -*/ - -// Transform X value from logical to device -// warning: this function can only be used for this purpose -// because no rotation is involved when mapping logical to device coordinates -// mirror and scaling for x and y will be part of the matrix -// if you have a matrix that is rotated, eg a shape containing a matrix to place -// it in the logical coordinate system, use TransformPoint -inline double wxTransformMatrix::TransformX(double x) const -{ - //normally like this, but since no rotation is involved (only mirror and scale) - //we can do without Y -> m_matrix[1]{0] is -sin(rotation angle) and therefore zero - //(x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0])) - return (m_isIdentity ? x : (x * m_matrix[0][0] + m_matrix[2][0])); -} - -// Transform Y value from logical to device -// warning: this function can only be used for this purpose -// because no rotation is involved when mapping logical to device coordinates -// mirror and scaling for x and y will be part of the matrix -// if you have a matrix that is rotated, eg a shape containing a matrix to place -// it in the logical coordinate system, use TransformPoint -inline double wxTransformMatrix::TransformY(double y) const -{ - //normally like this, but since no rotation is involved (only mirror and scale) - //we can do without X -> m_matrix[0]{1] is sin(rotation angle) and therefore zero - //(x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1])) - return (m_isIdentity ? y : (y * m_matrix[1][1] + m_matrix[2][1])); -} - - -// Is the matrix the identity matrix? -// Each operation checks whether the result is still the identity matrix and sets a flag. -inline bool wxTransformMatrix::IsIdentity1() const -{ - return - ( wxIsSameDouble(m_matrix[0][0], 1.0) && - wxIsSameDouble(m_matrix[1][1], 1.0) && - wxIsSameDouble(m_matrix[2][2], 1.0) && - wxIsSameDouble(m_matrix[1][0], 0.0) && - wxIsSameDouble(m_matrix[2][0], 0.0) && - wxIsSameDouble(m_matrix[0][1], 0.0) && - wxIsSameDouble(m_matrix[2][1], 0.0) && - wxIsSameDouble(m_matrix[0][2], 0.0) && - wxIsSameDouble(m_matrix[1][2], 0.0) ); -} - -// Calculates the determinant of a 2 x 2 matrix -inline double wxCalculateDet(double a11, double a21, double a12, double a22) -{ - return a11 * a22 - a12 * a21; -} - -#endif // _WX_MATRIXH__ diff --git a/src/common/matrix.cpp b/src/common/matrix.cpp deleted file mode 100644 index 69ef92cc2d..0000000000 --- a/src/common/matrix.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/matrix.cpp -// Purpose: wxTransformMatrix class -// Author: Chris Breeze, Julian Smart -// Modified by: Klaas Holwerda -// Created: 01/02/97 -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// Note: this is intended to be used in wxDC at some point to replace -// the current system of scaling/translation. It is not yet used. - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/matrix.h" - -#ifndef WX_PRECOMP - #include "wx/math.h" -#endif - -static const double pi = M_PI; - -wxTransformMatrix::wxTransformMatrix() -{ - m_isIdentity = false; - - Identity(); -} - -wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat) - : wxObject() -{ - (*this) = mat; -} - -double wxTransformMatrix::GetValue(int col, int row) const -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return 0.0; - - return m_matrix[col][row]; -} - -void wxTransformMatrix::SetValue(int col, int row, double value) -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return; - - m_matrix[col][row] = value; - m_isIdentity = IsIdentity1(); -} - -void wxTransformMatrix::operator = (const wxTransformMatrix& mat) -{ - int i, j; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - m_matrix[i][j] = mat.m_matrix[i][j]; - } - } - m_isIdentity = mat.m_isIdentity; -} - -bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const -{ - if (m_isIdentity && mat.m_isIdentity) - return true; - - int i, j; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) ) - return false; - } - } - return true; -} - -bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const -{ - return (! ((*this) == mat)); -} - -double& wxTransformMatrix::operator()(int col, int row) -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return m_matrix[0][0]; - - return m_matrix[col][row]; -} - -double wxTransformMatrix::operator()(int col, int row) const -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return 0.0; - - return m_matrix[col][row]; -} - -// Invert matrix -bool wxTransformMatrix::Invert() -{ - double inverseMatrix[3][3]; - - // calculate the adjoint - inverseMatrix[0][0] = wxCalculateDet(m_matrix[1][1],m_matrix[2][1],m_matrix[1][2],m_matrix[2][2]); - inverseMatrix[0][1] = -wxCalculateDet(m_matrix[0][1],m_matrix[2][1],m_matrix[0][2],m_matrix[2][2]); - inverseMatrix[0][2] = wxCalculateDet(m_matrix[0][1],m_matrix[1][1],m_matrix[0][2],m_matrix[1][2]); - - inverseMatrix[1][0] = -wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][2],m_matrix[2][2]); - inverseMatrix[1][1] = wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][2],m_matrix[2][2]); - inverseMatrix[1][2] = -wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][2],m_matrix[1][2]); - - inverseMatrix[2][0] = wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][1],m_matrix[2][1]); - inverseMatrix[2][1] = -wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][1],m_matrix[2][1]); - inverseMatrix[2][2] = wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][1],m_matrix[1][1]); - - // now divide by the determinant - double det = m_matrix[0][0] * inverseMatrix[0][0] + m_matrix[0][1] * inverseMatrix[1][0] + m_matrix[0][2] * inverseMatrix[2][0]; - if ( wxIsNullDouble(det) ) - return false; - - inverseMatrix[0][0] /= det; inverseMatrix[1][0] /= det; inverseMatrix[2][0] /= det; - inverseMatrix[0][1] /= det; inverseMatrix[1][1] /= det; inverseMatrix[2][1] /= det; - inverseMatrix[0][2] /= det; inverseMatrix[1][2] /= det; inverseMatrix[2][2] /= det; - - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - m_matrix[i][j] = inverseMatrix[i][j]; - } - } - m_isIdentity = IsIdentity1(); - return true; -} - -// Make into identity matrix -bool wxTransformMatrix::Identity() -{ - m_matrix[0][0] = m_matrix[1][1] = m_matrix[2][2] = 1.0; - m_matrix[1][0] = m_matrix[2][0] = m_matrix[0][1] = m_matrix[2][1] = m_matrix[0][2] = m_matrix[1][2] = 0.0; - m_isIdentity = true; - - return true; -} - -// Scale by scale (isotropic scaling i.e. the same in x and y): -// | scale 0 0 | -// matrix' = | 0 scale 0 | x matrix -// | 0 0 scale | -// -bool wxTransformMatrix::Scale(double scale) -{ - int i, j; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - m_matrix[i][j] *= scale; - } - } - m_isIdentity = IsIdentity1(); - - return true; -} - - -// scale a matrix in 2D -// -// xs 0 xc(1-xs) -// 0 ys yc(1-ys) -// 0 0 1 -// -wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc) -{ - double r00,r10,r20,r01,r11,r21; - - if (m_isIdentity) - { - double tx = xc*(1-xs); - double ty = yc*(1-ys); - r00 = xs; - r10 = 0; - r20 = tx; - r01 = 0; - r11 = ys; - r21 = ty; - } - else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) ) - { - double tx = xc*(1-xs); - double ty = yc*(1-ys); - r00 = xs * m_matrix[0][0]; - r10 = xs * m_matrix[1][0]; - r20 = xs * m_matrix[2][0] + tx; - r01 = ys * m_matrix[0][1]; - r11 = ys * m_matrix[1][1]; - r21 = ys * m_matrix[2][1] + ty; - } - else - { - r00 = xs * m_matrix[0][0]; - r10 = xs * m_matrix[1][0]; - r20 = xs * m_matrix[2][0]; - r01 = ys * m_matrix[0][1]; - r11 = ys * m_matrix[1][1]; - r21 = ys * m_matrix[2][1]; - } - - m_matrix[0][0] = r00; - m_matrix[1][0] = r10; - m_matrix[2][0] = r20; - m_matrix[0][1] = r01; - m_matrix[1][1] = r11; - m_matrix[2][1] = r21; - -/* or like this - // first translate to origin O - (*this).Translate(-x_cen, -y_cen); - - // now do the scaling - wxTransformMatrix scale; - scale.m_matrix[0][0] = x_fac; - scale.m_matrix[1][1] = y_fac; - scale.m_isIdentity = IsIdentity1(); - - *this = scale * (*this); - - // translate back from origin to x_cen, y_cen - (*this).Translate(x_cen, y_cen); -*/ - - m_isIdentity = IsIdentity1(); - - return *this; -} - - -// mirror a matrix in x, y -// -// -1 0 0 Y-mirror -// 0 -1 0 X-mirror -// 0 0 -1 Z-mirror -wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y) -{ - wxTransformMatrix temp; - if (x) - { - temp.m_matrix[1][1] = -1; - temp.m_isIdentity=false; - } - if (y) - { - temp.m_matrix[0][0] = -1; - temp.m_isIdentity=false; - } - - *this = temp * (*this); - m_isIdentity = IsIdentity1(); - return *this; -} - -// Translate by dx, dy: -// | 1 0 dx | -// matrix' = | 0 1 dy | x matrix -// | 0 0 1 | -// -bool wxTransformMatrix::Translate(double dx, double dy) -{ - int i; - for (i = 0; i < 3; i++) - m_matrix[i][0] += dx * m_matrix[i][2]; - for (i = 0; i < 3; i++) - m_matrix[i][1] += dy * m_matrix[i][2]; - - m_isIdentity = IsIdentity1(); - - return true; -} - -// Rotate clockwise by the given number of degrees: -// | cos sin 0 | -// matrix' = | -sin cos 0 | x matrix -// | 0 0 1 | -bool wxTransformMatrix::Rotate(double degrees) -{ - Rotate(-degrees,0,0); - return true; -} - -// counter clockwise rotate around a point -// -// cos(r) -sin(r) x(1-cos(r))+y(sin(r) -// sin(r) cos(r) y(1-cos(r))-x(sin(r) -// 0 0 1 -wxTransformMatrix& wxTransformMatrix::Rotate(const double °rees, const double &x, const double &y) -{ - double angle = degrees * pi / 180.0; - double c = cos(angle); - double s = sin(angle); - double r00,r10,r20,r01,r11,r21; - - if (m_isIdentity) - { - double tx = x*(1-c)+y*s; - double ty = y*(1-c)-x*s; - r00 = c ; - r10 = -s; - r20 = tx; - r01 = s; - r11 = c; - r21 = ty; - } - else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) ) - { - double tx = x*(1-c)+y*s; - double ty = y*(1-c)-x*s; - r00 = c * m_matrix[0][0] - s * m_matrix[0][1] + tx * m_matrix[0][2]; - r10 = c * m_matrix[1][0] - s * m_matrix[1][1] + tx * m_matrix[1][2]; - r20 = c * m_matrix[2][0] - s * m_matrix[2][1] + tx;// * m_matrix[2][2]; - r01 = c * m_matrix[0][1] + s * m_matrix[0][0] + ty * m_matrix[0][2]; - r11 = c * m_matrix[1][1] + s * m_matrix[1][0] + ty * m_matrix[1][2]; - r21 = c * m_matrix[2][1] + s * m_matrix[2][0] + ty;// * m_matrix[2][2]; - } - else - { - r00 = c * m_matrix[0][0] - s * m_matrix[0][1]; - r10 = c * m_matrix[1][0] - s * m_matrix[1][1]; - r20 = c * m_matrix[2][0] - s * m_matrix[2][1]; - r01 = c * m_matrix[0][1] + s * m_matrix[0][0]; - r11 = c * m_matrix[1][1] + s * m_matrix[1][0]; - r21 = c * m_matrix[2][1] + s * m_matrix[2][0]; - } - - m_matrix[0][0] = r00; - m_matrix[1][0] = r10; - m_matrix[2][0] = r20; - m_matrix[0][1] = r01; - m_matrix[1][1] = r11; - m_matrix[2][1] = r21; - -/* or like this - wxTransformMatrix rotate; - rotate.m_matrix[2][0] = tx; - rotate.m_matrix[2][1] = ty; - - rotate.m_matrix[0][0] = c; - rotate.m_matrix[0][1] = s; - - rotate.m_matrix[1][0] = -s; - rotate.m_matrix[1][1] = c; - - rotate.m_isIdentity=false; - *this = rotate * (*this); -*/ - m_isIdentity = IsIdentity1(); - - return *this; -} - -// Transform a point from logical to device coordinates -bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const -{ - if (IsIdentity()) - { - tx = x; ty = y; return true; - } - - tx = x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]; - ty = x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]; - - return true; -} - -// Transform a point from device to logical coordinates. - -// Example of use: -// wxTransformMatrix mat = dc.GetTransformation(); -// mat.Invert(); -// mat.InverseTransformPoint(x, y, x1, y1); -// OR (shorthand:) -// dc.LogicalToDevice(x, y, x1, y1); -// The latter is slightly less efficient if we're doing several -// conversions, since the matrix is inverted several times. -bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const -{ - if (IsIdentity()) - { - tx = x; - ty = y; - return true; - } - - const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2]; - if ( wxIsNullDouble(z) ) - return false; - - tx = x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; - ty = x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; - return true; -} - -wxTransformMatrix& wxTransformMatrix::operator*=(const double& t) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j]*= t; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator/=(const double& t) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j]/= t; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j] += mat.m_matrix[i][j]; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j] -= mat.m_matrix[i][j]; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat) -{ - - if (mat.m_isIdentity) - return *this; - if (m_isIdentity) - { - *this = mat; - return *this; - } - else - { - wxTransformMatrix result; - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - double sum = 0; - for (int k = 0; k < 3; k++) - sum += m_matrix[k][i] * mat.m_matrix[j][k]; - result.m_matrix[j][i] = sum; - } - } - *this = result; - } - - m_isIdentity = IsIdentity1(); - return *this; -} - - -// constant operators -wxTransformMatrix wxTransformMatrix::operator*(const double& t) const -{ - wxTransformMatrix result = *this; - result *= t; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -wxTransformMatrix wxTransformMatrix::operator/(const double& t) const -{ - wxTransformMatrix result = *this; -// wxASSERT(t!=0); - result /= t; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const -{ - wxTransformMatrix result = *this; - result += m; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const -{ - wxTransformMatrix result = *this; - result -= m; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - - -wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const -{ - wxTransformMatrix result = *this; - result *= m; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - - -wxTransformMatrix wxTransformMatrix::operator-() const -{ - wxTransformMatrix result = *this; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - result.m_matrix[i][j] = -(this->m_matrix[i][j]); - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -static double CheckInt(double getal) -{ - // check if the number is very close to an integer - if ( (ceil(getal) - getal) < 0.0001) - return ceil(getal); - - else if ( (getal - floor(getal)) < 0.0001) - return floor(getal); - - return getal; - -} - -double wxTransformMatrix::Get_scaleX() -{ - double scale_factor; - double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); - if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) - scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi); - else - scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! - - scale_factor = CheckInt(scale_factor); - if (scale_factor < 0) - scale_factor = -scale_factor; - - return scale_factor; -} - -double wxTransformMatrix::Get_scaleY() -{ - double scale_factor; - double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); - if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) - scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi); - else - scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! - - scale_factor = CheckInt(scale_factor); - if (scale_factor < 0) - - scale_factor = -scale_factor; - - return scale_factor; - -} - -double wxTransformMatrix::GetRotation() -{ - double temp1 = GetValue(0,0); // for angle calculation - double temp2 = GetValue(0,1); // - - // Rotation - double rot_angle = atan2(temp2,temp1)*180/pi; - - rot_angle = CheckInt(rot_angle); - return rot_angle; -} - -void wxTransformMatrix::SetRotation(double rotation) -{ - double x=GetValue(2,0); - double y=GetValue(2,1); - Rotate(-GetRotation(), x, y); - Rotate(rotation, x, y); -} diff --git a/tests/allheaders.h b/tests/allheaders.h index 7da480582a..4915ad7efb 100644 --- a/tests/allheaders.h +++ b/tests/allheaders.h @@ -217,7 +217,6 @@ #include #include #include -#include #include #include #include From 13700025be5cf2c8d9a7e5b99e2cbf934234f6a2 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Tue, 6 Oct 2020 22:06:51 +0300 Subject: [PATCH 091/105] Add wx/private/unicode.h --- include/wx/private/unicode.h | 16 ++++++++++++++++ src/common/strconv.cpp | 3 ++- src/common/ustring.cpp | 36 +----------------------------------- 3 files changed, 19 insertions(+), 36 deletions(-) create mode 100644 include/wx/private/unicode.h diff --git a/include/wx/private/unicode.h b/include/wx/private/unicode.h new file mode 100644 index 0000000000..6c81c23504 --- /dev/null +++ b/include/wx/private/unicode.h @@ -0,0 +1,16 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/private/unicode.h +// Purpose: Unicode private declsrations +// Author: Pavel Tyunin +// Created: 2020-10-06 +// Copyright: (c) 2020 Pavel Tyunin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_UNICODEH__ +#define _WX_PRIVATE_UNICODEH__ + +// this table gives the length of the UTF-8 encoding from its first character: +extern const unsigned char tableUtf8Lengths[256]; + +#endif // _WX_PRIVATE_UNICODEH__ diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index 04f6e451ec..d09b5ff2a4 100644 --- a/src/common/strconv.cpp +++ b/src/common/strconv.cpp @@ -46,6 +46,7 @@ #include "wx/encconv.h" #include "wx/fontmap.h" +#include "wx/private/unicode.h" #ifdef __DARWIN__ #include "wx/osx/core/private/strconv_cf.h" @@ -921,7 +922,7 @@ const wxUint32 wxUnicodePUA = 0x100000; const wxUint32 wxUnicodePUAEnd = wxUnicodePUA + 256; // this table gives the length of the UTF-8 encoding from its first character: -const unsigned char tableUtf8Lengths[256] = { +extern const unsigned char tableUtf8Lengths[256] = { // single-byte sequences (ASCII): 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00..0F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10..1F diff --git a/src/common/ustring.cpp b/src/common/ustring.cpp index 6e1768064b..531ee41b9c 100644 --- a/src/common/ustring.cpp +++ b/src/common/ustring.cpp @@ -15,6 +15,7 @@ #endif #include "wx/ustring.h" +#include "wx/private/unicode.h" #ifndef WX_PRECOMP #include "wx/crt.h" @@ -67,41 +68,6 @@ wxUString &wxUString::assignFromAscii( const char *str, size_type n ) // UTF-8 // ---------------------------------------------------------------------------- -// this table gives the length of the UTF-8 encoding from its first character: -const unsigned char tableUtf8Lengths[256] = { - // single-byte sequences (ASCII): - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00..0F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10..1F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20..2F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30..3F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40..4F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 50..5F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60..6F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 70..7F - - // these are invalid: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80..8F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90..9F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A0..AF - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B0..BF - 0, 0, // C0,C1 - - // two-byte sequences: - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C2..CF - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D0..DF - - // three-byte sequences: - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E0..EF - - // four-byte sequences: - 4, 4, 4, 4, 4, // F0..F4 - - // these are invalid again (5- or 6-byte - // sequences and sequences for code points - // above U+10FFFF, as restricted by RFC 3629): - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F5..FF -}; - wxUString &wxUString::assignFromUTF8( const char *str ) { if (!str) From 240fcee90ead3ab8207cc54f7e7c10303c6e1018 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Tue, 6 Oct 2020 22:34:52 +0300 Subject: [PATCH 092/105] Move wxIsUTF8Prefix() to convauto.cpp --- include/wx/strconv.h | 2 -- src/common/convauto.cpp | 21 +++++++++++++++++++++ src/common/strconv.cpp | 20 -------------------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/include/wx/strconv.h b/include/wx/strconv.h index 21c5f136b1..c1b070d36a 100644 --- a/include/wx/strconv.h +++ b/include/wx/strconv.h @@ -387,8 +387,6 @@ private: int m_options; }; -bool wxIsUTF8Prefix(const char *src, size_t len); - // ---------------------------------------------------------------------------- // wxMBConvUTF16Base: for both LE and BE variants // ---------------------------------------------------------------------------- diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp index 840841f5b6..9f3be27802 100644 --- a/src/common/convauto.cpp +++ b/src/common/convauto.cpp @@ -23,6 +23,7 @@ #endif #include "wx/convauto.h" +#include "wx/private/unicode.h" // we use latin1 by default as it seems the least bad choice: the files we need // to detect input of don't always come from the user system (they are often @@ -266,6 +267,26 @@ bool wxConvAuto::InitFromInput(const char *src, size_t len) return true; } +// checks if the input can be the beginning of a valid UTF-8 string +static bool wxIsUTF8Prefix(const char *src, size_t len) +{ + unsigned char l; + for ( size_t i = 0; i < len; ++i ) + { + l = tableUtf8Lengths[(unsigned char)src[i]]; + if ( !l ) + return false; // invalid leading byte + while ( --l ) + { + if ( ++i == len ) + return true; // truncated sequence + if ( (src[i] & 0xC0) != 0x80 ) + return false; // invalid continuation byte + } + } + return true; +} + size_t wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, const char *src, size_t srcLen) const diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index d09b5ff2a4..23c2b0a545 100644 --- a/src/common/strconv.cpp +++ b/src/common/strconv.cpp @@ -1447,26 +1447,6 @@ size_t wxMBConvUTF8::FromWChar(char *buf, size_t n, return len; } -// checks if the input can be the beginning of a valid UTF-8 string -bool wxIsUTF8Prefix(const char *src, size_t len) -{ - unsigned char l; - for ( size_t i = 0; i < len; ++i ) - { - l = tableUtf8Lengths[(unsigned char)src[i]]; - if ( !l ) - return false; // invalid leading byte - while ( --l ) - { - if ( ++i == len ) - return true; // truncated sequence - if ( (src[i] & 0xC0) != 0x80 ) - return false; // invalid continuation byte - } - } - return true; -} - // ============================================================================ // UTF-16 // ============================================================================ From b536457e0787db7fae241b9e1525910307a5cdad Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Wed, 7 Oct 2020 15:41:15 +0300 Subject: [PATCH 093/105] Use tableUtf8Lengths[] in sringops.cpp too --- include/wx/stringops.h | 8 +++---- src/common/stringops.cpp | 47 ++++++++++------------------------------ 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/include/wx/stringops.h b/include/wx/stringops.h index 150554f341..dd46e6616c 100644 --- a/include/wx/stringops.h +++ b/include/wx/stringops.h @@ -94,15 +94,15 @@ struct WXDLLIMPEXP_BASE wxStringOperationsUtf8 return (c <= 0x7F) || (c >= 0xC2 && c <= 0xF4); } - // table of offsets to skip forward when iterating over UTF-8 sequence - static const unsigned char ms_utf8IterTable[256]; + // returns offset to skip forward when iterating over UTF-8 sequence + static unsigned char GetUTF8IterOffset(unsigned char c); template static void IncIter(Iterator& i) { wxASSERT( IsValidUtf8LeadByte(*i) ); - i += ms_utf8IterTable[(unsigned char)*i]; + i += GetUTF8IterOffset(*i); } template @@ -178,7 +178,7 @@ struct WXDLLIMPEXP_BASE wxStringOperationsUtf8 static size_t GetUtf8CharLength(char c) { wxASSERT( IsValidUtf8LeadByte(c) ); - return ms_utf8IterTable[(unsigned char)c]; + return GetUTF8IterOffset(c); } // decodes single UTF-8 character from UTF-8 string diff --git a/src/common/stringops.cpp b/src/common/stringops.cpp index 85629406a3..7cedab7cc0 100644 --- a/src/common/stringops.cpp +++ b/src/common/stringops.cpp @@ -23,6 +23,8 @@ #include "wx/stringops.h" #endif +#include "wx/private/unicode.h" + // =========================================================================== // implementation // =========================================================================== @@ -97,40 +99,13 @@ wxWxCharBuffer wxStringOperationsWchar::EncodeNChars(size_t n, const wxUniChar& // UTF-8 sequences lengths // --------------------------------------------------------------------------- -const unsigned char wxStringOperationsUtf8::ms_utf8IterTable[256] = { - // single-byte sequences (ASCII): - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00..0F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10..1F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20..2F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30..3F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40..4F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 50..5F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60..6F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 70..7F - - // these are invalid, we use step 1 to skip - // over them (should never happen): - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80..8F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90..9F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0..AF - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0..BF - 1, 1, // C0,C1 - - // two-byte sequences: - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C2..CF - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D0..DF - - // three-byte sequences: - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E0..EF - - // four-byte sequences: - 4, 4, 4, 4, 4, // F0..F4 - - // these are invalid again (5- or 6-byte - // sequences and sequences for code points - // above U+10FFFF, as restricted by RFC 3629): - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F5..FF -}; +static unsigned char wxStringOperationsUtf8::GetUTF8IterOffset(unsigned char c) +{ + unsigned char l = tableUtf8Lengths[c]; + if ( !l ) //skip over invalid characters + l = 1; + return l; +} // --------------------------------------------------------------------------- // UTF-8 operations @@ -166,7 +141,7 @@ bool wxStringOperationsUtf8::IsValidUtf8String(const char *str, size_t len) { // if the string is not NULL-terminated, verify we have enough // bytes in it left for current character's encoding: - if ( c + ms_utf8IterTable[*c] > end ) + if ( c + GetUTF8IterOffset(*c) > end ) return false; } @@ -364,7 +339,7 @@ wxCharBuffer wxStringOperationsUtf8::EncodeNChars(size_t n, const wxUniChar& ch) { Utf8CharBuffer once(EncodeChar(ch)); // the IncIter() table can be used to determine the length of ch's encoding: - size_t len = ms_utf8IterTable[(unsigned char)once.data[0]]; + size_t len = GetUTF8IterOffset(once.data[0]); wxCharBuffer buf(n * len); char *ptr = buf.data(); From 1cbcf24832c978ea72f31542090d90456f0afefb Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Wed, 7 Oct 2020 17:02:06 +0300 Subject: [PATCH 094/105] Make leading nulls a special case to avoid breaking decoding some short strings in fallback encoding --- src/common/convauto.cpp | 7 +++++-- tests/mbconv/convautotest.cpp | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp index 9f3be27802..8778295207 100644 --- a/src/common/convauto.cpp +++ b/src/common/convauto.cpp @@ -334,9 +334,12 @@ wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, // to the fall-back conversion in this case as it would prevent us from // decoding UTF-8 input when fed it byte by byte, as done by // wxTextInputStream, for example - // 2 extra bytes are needed for inputs that start with 1 or 2 null bytes + // up to 2 extra bytes are needed for inputs that start with null bytes // that look like the start of UTF-32BE BOM, but can be in UTF-8 too - if ( srcLen < 2 + m_conv->GetMaxCharLen() && wxIsUTF8Prefix(src, srcLen) ) + size_t nNull = 0; + if ( srcLen != wxNO_LEN && srcLen >= 2 && !src[0] ) + nNull = ( src[1]? 1 : 2 ); + if ( srcLen < nNull + m_conv->GetMaxCharLen() && wxIsUTF8Prefix(src, srcLen) ) return wxCONV_FAILED; // if the conversion failed but we didn't really detect anything and diff --git a/tests/mbconv/convautotest.cpp b/tests/mbconv/convautotest.cpp index 6eaa24b155..27839f93a5 100644 --- a/tests/mbconv/convautotest.cpp +++ b/tests/mbconv/convautotest.cpp @@ -47,6 +47,7 @@ private: CPPUNIT_TEST( UTF8NoBom ); CPPUNIT_TEST( Fallback ); CPPUNIT_TEST( FallbackMultibyte ); + CPPUNIT_TEST( FallbackShort ); CPPUNIT_TEST( StreamUTF8NoBOM ); CPPUNIT_TEST( StreamUTF8 ); CPPUNIT_TEST( StreamUTF16LE ); @@ -100,6 +101,7 @@ private: void UTF8NoBom(); void Fallback(); void FallbackMultibyte(); + void FallbackShort(); // test whether two lines of text are converted properly from a stream void TestTextStream(const char *src, @@ -222,6 +224,13 @@ void ConvAutoTestCase::FallbackMultibyte() #endif } +void ConvAutoTestCase::FallbackShort() +{ + TestFirstChar("\x61\x61\x61\xc4", 'a', 4, + ConvState(wxBOM_None, wxFONTENCODING_ISO8859_5, true), + wxFONTENCODING_ISO8859_5); +} + void ConvAutoTestCase::TestTextStream(const char *src, size_t srclength, const wxString& line1, From c9dd9e96a1bc834fad23435242bc83b793d987ed Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Wed, 7 Oct 2020 17:31:42 +0300 Subject: [PATCH 095/105] Allow decoding even shorter strings in fallback encoding Complete UTF-8 characters (except leading nulls) never appear in failed decoding attempts when the input is fed byte by byte. --- src/common/convauto.cpp | 30 ++++++++++++++---------------- tests/mbconv/convautotest.cpp | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp index 8778295207..708096de5d 100644 --- a/src/common/convauto.cpp +++ b/src/common/convauto.cpp @@ -267,24 +267,21 @@ bool wxConvAuto::InitFromInput(const char *src, size_t len) return true; } -// checks if the input can be the beginning of a valid UTF-8 string -static bool wxIsUTF8Prefix(const char *src, size_t len) +// checks if the input can be the beginning of a valid UTF-8 sequence +static bool wxCanBeUTF8SequencePrefix(const char *src, size_t len) { - unsigned char l; - for ( size_t i = 0; i < len; ++i ) + size_t i = 0; + unsigned char l = tableUtf8Lengths[(unsigned char)src[i]]; + if ( !l ) + return false; // invalid leading byte + while ( --l ) { - l = tableUtf8Lengths[(unsigned char)src[i]]; - if ( !l ) - return false; // invalid leading byte - while ( --l ) - { - if ( ++i == len ) - return true; // truncated sequence - if ( (src[i] & 0xC0) != 0x80 ) - return false; // invalid continuation byte - } + if ( ++i == len ) + return true; // truncated sequence + if ( (src[i] & 0xC0) != 0x80 ) + return false; // invalid continuation byte } - return true; + return false; // complete sequence } size_t @@ -339,7 +336,8 @@ wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, size_t nNull = 0; if ( srcLen != wxNO_LEN && srcLen >= 2 && !src[0] ) nNull = ( src[1]? 1 : 2 ); - if ( srcLen < nNull + m_conv->GetMaxCharLen() && wxIsUTF8Prefix(src, srcLen) ) + if ( srcLen < nNull + m_conv->GetMaxCharLen() && + wxCanBeUTF8SequencePrefix(src + nNull, srcLen - nNull) ) return wxCONV_FAILED; // if the conversion failed but we didn't really detect anything and diff --git a/tests/mbconv/convautotest.cpp b/tests/mbconv/convautotest.cpp index 27839f93a5..12e19c21ed 100644 --- a/tests/mbconv/convautotest.cpp +++ b/tests/mbconv/convautotest.cpp @@ -226,7 +226,7 @@ void ConvAutoTestCase::FallbackMultibyte() void ConvAutoTestCase::FallbackShort() { - TestFirstChar("\x61\x61\x61\xc4", 'a', 4, + TestFirstChar("\x61\xc4", 'a', 2, ConvState(wxBOM_None, wxFONTENCODING_ISO8859_5, true), wxFONTENCODING_ISO8859_5); } From 0ab3b4eac71d442cf56b14cdfd8bc1da9bc69bd7 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Wed, 7 Oct 2020 17:53:43 +0300 Subject: [PATCH 096/105] Fix UTF-8 build --- src/common/stringops.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/stringops.cpp b/src/common/stringops.cpp index 7cedab7cc0..84017ae523 100644 --- a/src/common/stringops.cpp +++ b/src/common/stringops.cpp @@ -99,7 +99,7 @@ wxWxCharBuffer wxStringOperationsWchar::EncodeNChars(size_t n, const wxUniChar& // UTF-8 sequences lengths // --------------------------------------------------------------------------- -static unsigned char wxStringOperationsUtf8::GetUTF8IterOffset(unsigned char c) +unsigned char wxStringOperationsUtf8::GetUTF8IterOffset(unsigned char c) { unsigned char l = tableUtf8Lengths[c]; if ( !l ) //skip over invalid characters From 365c3a2ae92fa2746f52678220c0864be4814d20 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Wed, 7 Oct 2020 23:15:10 +0200 Subject: [PATCH 097/105] Revert "Get rid of unused wxTransformMatrix" wxTransformMatrix is undocumented but it is appartently in use so it has to be present in the library. This reverts commit 3e88df56f5afa2d0de4c4a563788f8476d749eb8. --- Makefile.in | 21 + build/bakefiles/files.bkl | 2 + build/cmake/files.cmake | 2 + build/files | 2 + build/msw/makefile.bcc | 28 + build/msw/makefile.gcc | 28 + build/msw/makefile.vc | 28 + build/msw/wx_core.vcxproj | 2 + build/msw/wx_core.vcxproj.filters | 6 + build/msw/wx_vc7_core.vcproj | 6 + build/msw/wx_vc8_core.vcproj | 8 + build/msw/wx_vc9_core.vcproj | 8 + build/osx/wxcocoa.xcodeproj/project.pbxproj | 8 + build/osx/wxiphone.xcodeproj/project.pbxproj | 4 + include/wx/matrix.h | 234 ++++++++ src/common/matrix.cpp | 600 +++++++++++++++++++ tests/allheaders.h | 1 + 17 files changed, 988 insertions(+) create mode 100644 include/wx/matrix.h create mode 100644 src/common/matrix.cpp diff --git a/Makefile.in b/Makefile.in index 83f5f3489d..62beaa8482 100644 --- a/Makefile.in +++ b/Makefile.in @@ -3879,6 +3879,7 @@ COND_USE_GUI_1_ALL_GUI_HEADERS = \ wx/listbase.h \ wx/listbook.h \ wx/listctrl.h \ + wx/matrix.h \ wx/menuitem.h \ wx/metafile.h \ wx/minifram.h \ @@ -4515,6 +4516,7 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS = \ monodll_lboxcmn.o \ monodll_listctrlcmn.o \ monodll_markupparser.o \ + monodll_matrix.o \ monodll_menucmn.o \ monodll_modalhook.o \ monodll_mousemanager.o \ @@ -4775,6 +4777,7 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS = \ monodll_lboxcmn.o \ monodll_listctrlcmn.o \ monodll_markupparser.o \ + monodll_matrix.o \ monodll_menucmn.o \ monodll_modalhook.o \ monodll_mousemanager.o \ @@ -6500,6 +6503,7 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS_1 = \ monolib_lboxcmn.o \ monolib_listctrlcmn.o \ monolib_markupparser.o \ + monolib_matrix.o \ monolib_menucmn.o \ monolib_modalhook.o \ monolib_mousemanager.o \ @@ -6760,6 +6764,7 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS_1 = \ monolib_lboxcmn.o \ monolib_listctrlcmn.o \ monolib_markupparser.o \ + monolib_matrix.o \ monolib_menucmn.o \ monolib_modalhook.o \ monolib_mousemanager.o \ @@ -8631,6 +8636,7 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS_2 = \ coredll_lboxcmn.o \ coredll_listctrlcmn.o \ coredll_markupparser.o \ + coredll_matrix.o \ coredll_menucmn.o \ coredll_modalhook.o \ coredll_mousemanager.o \ @@ -8891,6 +8897,7 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS_2 = \ coredll_lboxcmn.o \ coredll_listctrlcmn.o \ coredll_markupparser.o \ + coredll_matrix.o \ coredll_menucmn.o \ coredll_modalhook.o \ coredll_mousemanager.o \ @@ -10352,6 +10359,7 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS_3 = \ corelib_lboxcmn.o \ corelib_listctrlcmn.o \ corelib_markupparser.o \ + corelib_matrix.o \ corelib_menucmn.o \ corelib_modalhook.o \ corelib_mousemanager.o \ @@ -10612,6 +10620,7 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS_3 = \ corelib_lboxcmn.o \ corelib_listctrlcmn.o \ corelib_markupparser.o \ + corelib_matrix.o \ corelib_menucmn.o \ corelib_modalhook.o \ corelib_mousemanager.o \ @@ -20463,6 +20472,9 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP) @COND_USE_GUI_1@monodll_markupparser.o: $(srcdir)/src/common/markupparser.cpp $(MONODLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/markupparser.cpp +@COND_USE_GUI_1@monodll_matrix.o: $(srcdir)/src/common/matrix.cpp $(MONODLL_ODEP) +@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/matrix.cpp + @COND_USE_GUI_1@monodll_menucmn.o: $(srcdir)/src/common/menucmn.cpp $(MONODLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/menucmn.cpp @@ -25728,6 +25740,9 @@ monolib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1@monolib_markupparser.o: $(srcdir)/src/common/markupparser.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/markupparser.cpp +@COND_USE_GUI_1@monolib_matrix.o: $(srcdir)/src/common/matrix.cpp $(MONOLIB_ODEP) +@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/matrix.cpp + @COND_USE_GUI_1@monolib_menucmn.o: $(srcdir)/src/common/menucmn.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/menucmn.cpp @@ -31074,6 +31089,9 @@ coredll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(COREDLL_ODEP) @COND_USE_GUI_1@coredll_markupparser.o: $(srcdir)/src/common/markupparser.cpp $(COREDLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/common/markupparser.cpp +@COND_USE_GUI_1@coredll_matrix.o: $(srcdir)/src/common/matrix.cpp $(COREDLL_ODEP) +@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/common/matrix.cpp + @COND_USE_GUI_1@coredll_menucmn.o: $(srcdir)/src/common/menucmn.cpp $(COREDLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/common/menucmn.cpp @@ -35328,6 +35346,9 @@ corelib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(CORELIB_ODEP) @COND_USE_GUI_1@corelib_markupparser.o: $(srcdir)/src/common/markupparser.cpp $(CORELIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/common/markupparser.cpp +@COND_USE_GUI_1@corelib_matrix.o: $(srcdir)/src/common/matrix.cpp $(CORELIB_ODEP) +@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/common/matrix.cpp + @COND_USE_GUI_1@corelib_menucmn.o: $(srcdir)/src/common/menucmn.cpp $(CORELIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/common/menucmn.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 7752bbe117..6b906206a4 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -883,6 +883,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/common/lboxcmn.cpp src/common/listctrlcmn.cpp src/common/markupparser.cpp + src/common/matrix.cpp src/common/menucmn.cpp src/common/modalhook.cpp src/common/mousemanager.cpp @@ -1187,6 +1188,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/listbase.h wx/listbook.h wx/listctrl.h + wx/matrix.h wx/menuitem.h wx/metafile.h wx/minifram.h diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index 3d76134938..8165d51792 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -787,6 +787,7 @@ set(GUI_CMN_SRC src/common/lboxcmn.cpp src/common/listctrlcmn.cpp src/common/markupparser.cpp + src/common/matrix.cpp src/common/menucmn.cpp src/common/modalhook.cpp src/common/mousemanager.cpp @@ -1096,6 +1097,7 @@ set(GUI_CMN_HDR wx/listbase.h wx/listbook.h wx/listctrl.h + wx/matrix.h wx/menuitem.h wx/metafile.h wx/minifram.h diff --git a/build/files b/build/files index cf9a6341c1..39a49b19c6 100644 --- a/build/files +++ b/build/files @@ -806,6 +806,7 @@ GUI_CMN_SRC = src/common/lboxcmn.cpp src/common/listctrlcmn.cpp src/common/markupparser.cpp + src/common/matrix.cpp src/common/menucmn.cpp src/common/modalhook.cpp src/common/mousemanager.cpp @@ -1100,6 +1101,7 @@ GUI_CMN_HDR = wx/listbook.h wx/listbox.h wx/listctrl.h + wx/matrix.h wx/mdi.h wx/menu.h wx/menuitem.h diff --git a/build/msw/makefile.bcc b/build/msw/makefile.bcc index fb0f397081..1ca436dce3 100644 --- a/build/msw/makefile.bcc +++ b/build/msw/makefile.bcc @@ -2028,6 +2028,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.obj \ $(OBJS)\monodll_listctrlcmn.obj \ $(OBJS)\monodll_markupparser.obj \ + $(OBJS)\monodll_matrix.obj \ $(OBJS)\monodll_menucmn.obj \ $(OBJS)\monodll_modalhook.obj \ $(OBJS)\monodll_mousemanager.obj \ @@ -2354,6 +2355,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.obj \ $(OBJS)\monodll_listctrlcmn.obj \ $(OBJS)\monodll_markupparser.obj \ + $(OBJS)\monodll_matrix.obj \ $(OBJS)\monodll_menucmn.obj \ $(OBJS)\monodll_modalhook.obj \ $(OBJS)\monodll_mousemanager.obj \ @@ -2860,6 +2862,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.obj \ $(OBJS)\monolib_listctrlcmn.obj \ $(OBJS)\monolib_markupparser.obj \ + $(OBJS)\monolib_matrix.obj \ $(OBJS)\monolib_menucmn.obj \ $(OBJS)\monolib_modalhook.obj \ $(OBJS)\monolib_mousemanager.obj \ @@ -3186,6 +3189,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.obj \ $(OBJS)\monolib_listctrlcmn.obj \ $(OBJS)\monolib_markupparser.obj \ + $(OBJS)\monolib_matrix.obj \ $(OBJS)\monolib_menucmn.obj \ $(OBJS)\monolib_modalhook.obj \ $(OBJS)\monolib_mousemanager.obj \ @@ -3565,6 +3569,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.obj \ $(OBJS)\coredll_listctrlcmn.obj \ $(OBJS)\coredll_markupparser.obj \ + $(OBJS)\coredll_matrix.obj \ $(OBJS)\coredll_menucmn.obj \ $(OBJS)\coredll_modalhook.obj \ $(OBJS)\coredll_mousemanager.obj \ @@ -3891,6 +3896,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.obj \ $(OBJS)\coredll_listctrlcmn.obj \ $(OBJS)\coredll_markupparser.obj \ + $(OBJS)\coredll_matrix.obj \ $(OBJS)\coredll_menucmn.obj \ $(OBJS)\coredll_modalhook.obj \ $(OBJS)\coredll_mousemanager.obj \ @@ -4236,6 +4242,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.obj \ $(OBJS)\corelib_listctrlcmn.obj \ $(OBJS)\corelib_markupparser.obj \ + $(OBJS)\corelib_matrix.obj \ $(OBJS)\corelib_menucmn.obj \ $(OBJS)\corelib_modalhook.obj \ $(OBJS)\corelib_mousemanager.obj \ @@ -4562,6 +4569,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.obj \ $(OBJS)\corelib_listctrlcmn.obj \ $(OBJS)\corelib_markupparser.obj \ + $(OBJS)\corelib_matrix.obj \ $(OBJS)\corelib_menucmn.obj \ $(OBJS)\corelib_modalhook.obj \ $(OBJS)\corelib_mousemanager.obj \ @@ -8395,6 +8403,11 @@ $(OBJS)\monodll_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif +!if "$(USE_GUI)" == "1" +$(OBJS)\monodll_matrix.obj: ..\..\src\common\matrix.cpp + $(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\common\matrix.cpp +!endif + !if "$(USE_GUI)" == "1" $(OBJS)\monodll_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -10944,6 +10957,11 @@ $(OBJS)\monolib_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif +!if "$(USE_GUI)" == "1" +$(OBJS)\monolib_matrix.obj: ..\..\src\common\matrix.cpp + $(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\matrix.cpp +!endif + !if "$(USE_GUI)" == "1" $(OBJS)\monolib_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -13451,6 +13469,11 @@ $(OBJS)\coredll_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif +!if "$(USE_GUI)" == "1" +$(OBJS)\coredll_matrix.obj: ..\..\src\common\matrix.cpp + $(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\common\matrix.cpp +!endif + !if "$(USE_GUI)" == "1" $(OBJS)\coredll_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -15181,6 +15204,11 @@ $(OBJS)\corelib_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif +!if "$(USE_GUI)" == "1" +$(OBJS)\corelib_matrix.obj: ..\..\src\common\matrix.cpp + $(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\common\matrix.cpp +!endif + !if "$(USE_GUI)" == "1" $(OBJS)\corelib_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\common\menucmn.cpp diff --git a/build/msw/makefile.gcc b/build/msw/makefile.gcc index bda89b0f3b..a5488e00a1 100644 --- a/build/msw/makefile.gcc +++ b/build/msw/makefile.gcc @@ -2053,6 +2053,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.o \ $(OBJS)\monodll_listctrlcmn.o \ $(OBJS)\monodll_markupparser.o \ + $(OBJS)\monodll_matrix.o \ $(OBJS)\monodll_menucmn.o \ $(OBJS)\monodll_modalhook.o \ $(OBJS)\monodll_mousemanager.o \ @@ -2381,6 +2382,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.o \ $(OBJS)\monodll_listctrlcmn.o \ $(OBJS)\monodll_markupparser.o \ + $(OBJS)\monodll_matrix.o \ $(OBJS)\monodll_menucmn.o \ $(OBJS)\monodll_modalhook.o \ $(OBJS)\monodll_mousemanager.o \ @@ -2891,6 +2893,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.o \ $(OBJS)\monolib_listctrlcmn.o \ $(OBJS)\monolib_markupparser.o \ + $(OBJS)\monolib_matrix.o \ $(OBJS)\monolib_menucmn.o \ $(OBJS)\monolib_modalhook.o \ $(OBJS)\monolib_mousemanager.o \ @@ -3219,6 +3222,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.o \ $(OBJS)\monolib_listctrlcmn.o \ $(OBJS)\monolib_markupparser.o \ + $(OBJS)\monolib_matrix.o \ $(OBJS)\monolib_menucmn.o \ $(OBJS)\monolib_modalhook.o \ $(OBJS)\monolib_mousemanager.o \ @@ -3612,6 +3616,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.o \ $(OBJS)\coredll_listctrlcmn.o \ $(OBJS)\coredll_markupparser.o \ + $(OBJS)\coredll_matrix.o \ $(OBJS)\coredll_menucmn.o \ $(OBJS)\coredll_modalhook.o \ $(OBJS)\coredll_mousemanager.o \ @@ -3940,6 +3945,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.o \ $(OBJS)\coredll_listctrlcmn.o \ $(OBJS)\coredll_markupparser.o \ + $(OBJS)\coredll_matrix.o \ $(OBJS)\coredll_menucmn.o \ $(OBJS)\coredll_modalhook.o \ $(OBJS)\coredll_mousemanager.o \ @@ -4291,6 +4297,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.o \ $(OBJS)\corelib_listctrlcmn.o \ $(OBJS)\corelib_markupparser.o \ + $(OBJS)\corelib_matrix.o \ $(OBJS)\corelib_menucmn.o \ $(OBJS)\corelib_modalhook.o \ $(OBJS)\corelib_mousemanager.o \ @@ -4619,6 +4626,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.o \ $(OBJS)\corelib_listctrlcmn.o \ $(OBJS)\corelib_markupparser.o \ + $(OBJS)\corelib_matrix.o \ $(OBJS)\corelib_menucmn.o \ $(OBJS)\corelib_modalhook.o \ $(OBJS)\corelib_mousemanager.o \ @@ -8699,6 +8707,11 @@ $(OBJS)\monodll_markupparser.o: ../../src/common/markupparser.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< endif +ifeq ($(USE_GUI),1) +$(OBJS)\monodll_matrix.o: ../../src/common/matrix.cpp + $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< +endif + ifeq ($(USE_GUI),1) $(OBJS)\monodll_menucmn.o: ../../src/common/menucmn.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< @@ -11248,6 +11261,11 @@ $(OBJS)\monolib_markupparser.o: ../../src/common/markupparser.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< endif +ifeq ($(USE_GUI),1) +$(OBJS)\monolib_matrix.o: ../../src/common/matrix.cpp + $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< +endif + ifeq ($(USE_GUI),1) $(OBJS)\monolib_menucmn.o: ../../src/common/menucmn.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< @@ -13755,6 +13773,11 @@ $(OBJS)\coredll_markupparser.o: ../../src/common/markupparser.cpp $(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $< endif +ifeq ($(USE_GUI),1) +$(OBJS)\coredll_matrix.o: ../../src/common/matrix.cpp + $(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $< +endif + ifeq ($(USE_GUI),1) $(OBJS)\coredll_menucmn.o: ../../src/common/menucmn.cpp $(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $< @@ -15485,6 +15508,11 @@ $(OBJS)\corelib_markupparser.o: ../../src/common/markupparser.cpp $(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $< endif +ifeq ($(USE_GUI),1) +$(OBJS)\corelib_matrix.o: ../../src/common/matrix.cpp + $(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $< +endif + ifeq ($(USE_GUI),1) $(OBJS)\corelib_menucmn.o: ../../src/common/menucmn.cpp $(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $< diff --git a/build/msw/makefile.vc b/build/msw/makefile.vc index 72bc753c29..2852105611 100644 --- a/build/msw/makefile.vc +++ b/build/msw/makefile.vc @@ -2365,6 +2365,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.obj \ $(OBJS)\monodll_listctrlcmn.obj \ $(OBJS)\monodll_markupparser.obj \ + $(OBJS)\monodll_matrix.obj \ $(OBJS)\monodll_menucmn.obj \ $(OBJS)\monodll_modalhook.obj \ $(OBJS)\monodll_mousemanager.obj \ @@ -2691,6 +2692,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_lboxcmn.obj \ $(OBJS)\monodll_listctrlcmn.obj \ $(OBJS)\monodll_markupparser.obj \ + $(OBJS)\monodll_matrix.obj \ $(OBJS)\monodll_menucmn.obj \ $(OBJS)\monodll_modalhook.obj \ $(OBJS)\monodll_mousemanager.obj \ @@ -3203,6 +3205,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.obj \ $(OBJS)\monolib_listctrlcmn.obj \ $(OBJS)\monolib_markupparser.obj \ + $(OBJS)\monolib_matrix.obj \ $(OBJS)\monolib_menucmn.obj \ $(OBJS)\monolib_modalhook.obj \ $(OBJS)\monolib_mousemanager.obj \ @@ -3529,6 +3532,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_lboxcmn.obj \ $(OBJS)\monolib_listctrlcmn.obj \ $(OBJS)\monolib_markupparser.obj \ + $(OBJS)\monolib_matrix.obj \ $(OBJS)\monolib_menucmn.obj \ $(OBJS)\monolib_modalhook.obj \ $(OBJS)\monolib_mousemanager.obj \ @@ -3974,6 +3978,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.obj \ $(OBJS)\coredll_listctrlcmn.obj \ $(OBJS)\coredll_markupparser.obj \ + $(OBJS)\coredll_matrix.obj \ $(OBJS)\coredll_menucmn.obj \ $(OBJS)\coredll_modalhook.obj \ $(OBJS)\coredll_mousemanager.obj \ @@ -4300,6 +4305,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_lboxcmn.obj \ $(OBJS)\coredll_listctrlcmn.obj \ $(OBJS)\coredll_markupparser.obj \ + $(OBJS)\coredll_matrix.obj \ $(OBJS)\coredll_menucmn.obj \ $(OBJS)\coredll_modalhook.obj \ $(OBJS)\coredll_mousemanager.obj \ @@ -4651,6 +4657,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.obj \ $(OBJS)\corelib_listctrlcmn.obj \ $(OBJS)\corelib_markupparser.obj \ + $(OBJS)\corelib_matrix.obj \ $(OBJS)\corelib_menucmn.obj \ $(OBJS)\corelib_modalhook.obj \ $(OBJS)\corelib_mousemanager.obj \ @@ -4977,6 +4984,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_lboxcmn.obj \ $(OBJS)\corelib_listctrlcmn.obj \ $(OBJS)\corelib_markupparser.obj \ + $(OBJS)\corelib_matrix.obj \ $(OBJS)\corelib_menucmn.obj \ $(OBJS)\corelib_modalhook.obj \ $(OBJS)\corelib_mousemanager.obj \ @@ -9130,6 +9138,11 @@ $(OBJS)\monodll_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif +!if "$(USE_GUI)" == "1" +$(OBJS)\monodll_matrix.obj: ..\..\src\common\matrix.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\matrix.cpp +!endif + !if "$(USE_GUI)" == "1" $(OBJS)\monodll_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -11679,6 +11692,11 @@ $(OBJS)\monolib_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif +!if "$(USE_GUI)" == "1" +$(OBJS)\monolib_matrix.obj: ..\..\src\common\matrix.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\matrix.cpp +!endif + !if "$(USE_GUI)" == "1" $(OBJS)\monolib_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -14186,6 +14204,11 @@ $(OBJS)\coredll_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif +!if "$(USE_GUI)" == "1" +$(OBJS)\coredll_matrix.obj: ..\..\src\common\matrix.cpp + $(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\common\matrix.cpp +!endif + !if "$(USE_GUI)" == "1" $(OBJS)\coredll_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\common\menucmn.cpp @@ -15916,6 +15939,11 @@ $(OBJS)\corelib_markupparser.obj: ..\..\src\common\markupparser.cpp $(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\common\markupparser.cpp !endif +!if "$(USE_GUI)" == "1" +$(OBJS)\corelib_matrix.obj: ..\..\src\common\matrix.cpp + $(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\common\matrix.cpp +!endif + !if "$(USE_GUI)" == "1" $(OBJS)\corelib_menucmn.obj: ..\..\src\common\menucmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\common\menucmn.cpp diff --git a/build/msw/wx_core.vcxproj b/build/msw/wx_core.vcxproj index 2d84caa37c..8089f36d7b 100644 --- a/build/msw/wx_core.vcxproj +++ b/build/msw/wx_core.vcxproj @@ -541,6 +541,7 @@ + @@ -1337,6 +1338,7 @@ + diff --git a/build/msw/wx_core.vcxproj.filters b/build/msw/wx_core.vcxproj.filters index 57bc68602c..83c265118a 100644 --- a/build/msw/wx_core.vcxproj.filters +++ b/build/msw/wx_core.vcxproj.filters @@ -294,6 +294,9 @@ Common Sources + + Common Sources + Common Sources @@ -1615,6 +1618,9 @@ Common Headers + + Common Headers + Common Headers diff --git a/build/msw/wx_vc7_core.vcproj b/build/msw/wx_vc7_core.vcproj index ef9520b43f..ad378068ce 100644 --- a/build/msw/wx_vc7_core.vcproj +++ b/build/msw/wx_vc7_core.vcproj @@ -567,6 +567,9 @@ + + @@ -2474,6 +2477,9 @@ + + diff --git a/build/msw/wx_vc8_core.vcproj b/build/msw/wx_vc8_core.vcproj index a25ffbdd55..e956ab6df8 100644 --- a/build/msw/wx_vc8_core.vcproj +++ b/build/msw/wx_vc8_core.vcproj @@ -1161,6 +1161,10 @@ RelativePath="..\..\src\common\markupparser.cpp" > + + @@ -3800,6 +3804,10 @@ RelativePath="..\..\include\wx\propgrid\manager.h" > + + diff --git a/build/msw/wx_vc9_core.vcproj b/build/msw/wx_vc9_core.vcproj index f8d4cc4439..a6d3ec7b1d 100644 --- a/build/msw/wx_vc9_core.vcproj +++ b/build/msw/wx_vc9_core.vcproj @@ -1157,6 +1157,10 @@ RelativePath="..\..\src\common\markupparser.cpp" > + + @@ -3796,6 +3800,10 @@ RelativePath="..\..\include\wx\propgrid\manager.h" > + + diff --git a/build/osx/wxcocoa.xcodeproj/project.pbxproj b/build/osx/wxcocoa.xcodeproj/project.pbxproj index 771d6ce9fe..5ce91d315a 100644 --- a/build/osx/wxcocoa.xcodeproj/project.pbxproj +++ b/build/osx/wxcocoa.xcodeproj/project.pbxproj @@ -1766,6 +1766,9 @@ 9A178ED42D96329D8CBF9B89 /* tif_predict.c in Sources */ = {isa = PBXBuildFile; fileRef = 2FA01C426EAF38D3B9ED35AC /* tif_predict.c */; }; 9A178ED42D96329D8CBF9B8A /* tif_predict.c in Sources */ = {isa = PBXBuildFile; fileRef = 2FA01C426EAF38D3B9ED35AC /* tif_predict.c */; }; 9A178ED42D96329D8CBF9B8B /* tif_predict.c in Sources */ = {isa = PBXBuildFile; fileRef = 2FA01C426EAF38D3B9ED35AC /* tif_predict.c */; }; + 9A83D365AD1F37FA9C7030C2 /* matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF330EAACFA53877BE289896 /* matrix.cpp */; }; + 9A83D365AD1F37FA9C7030C3 /* matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF330EAACFA53877BE289896 /* matrix.cpp */; }; + 9A83D365AD1F37FA9C7030C4 /* matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF330EAACFA53877BE289896 /* matrix.cpp */; }; 9B3F9D04FB533D99B58BD519 /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 029486D6A2EC3DE0902A6A24 /* jfdctfst.c */; }; 9B3F9D04FB533D99B58BD51A /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 029486D6A2EC3DE0902A6A24 /* jfdctfst.c */; }; 9B3F9D04FB533D99B58BD51B /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 029486D6A2EC3DE0902A6A24 /* jfdctfst.c */; }; @@ -4754,6 +4757,7 @@ EEADAA811BBF3CBBB9E254FD /* xh_split.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_split.cpp; path = ../../src/xrc/xh_split.cpp; sourceTree = ""; }; EED7C691150139EFA35E8EBD /* utils_osx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = utils_osx.cpp; path = ../../src/osx/utils_osx.cpp; sourceTree = ""; }; EEE82083BFA430D5B58F8A04 /* regfree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regfree.c; path = ../../src/regex/regfree.c; sourceTree = ""; }; + EF330EAACFA53877BE289896 /* matrix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = matrix.cpp; path = ../../src/common/matrix.cpp; sourceTree = ""; }; F01DDE448E4C3983ACCE67FD /* appcmn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = appcmn.cpp; path = ../../src/common/appcmn.cpp; sourceTree = ""; }; F0905A1EBD653F6D82395602 /* xh_combo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_combo.cpp; path = ../../src/xrc/xh_combo.cpp; sourceTree = ""; }; F175D6E8E5723FC797701275 /* menucmn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = menucmn.cpp; path = ../../src/common/menucmn.cpp; sourceTree = ""; }; @@ -5529,6 +5533,7 @@ 9660AE8FEB7B3EDB857B9238 /* lboxcmn.cpp */, E1B1FBB2BCC43BA7A45E9438 /* listctrlcmn.cpp */, DA7F7633279936EFA0B9C5CF /* markupparser.cpp */, + EF330EAACFA53877BE289896 /* matrix.cpp */, F175D6E8E5723FC797701275 /* menucmn.cpp */, 58E7C516E2453A269280A404 /* modalhook.cpp */, D037EA567C253DEEA17E822B /* mousemanager.cpp */, @@ -7743,6 +7748,7 @@ CFF73578F04D357E83D1D832 /* lboxcmn.cpp in Sources */, 164010B26D363F5FA09785B8 /* listctrlcmn.cpp in Sources */, 2F7F5B9BBCD83D90B237A1A2 /* markupparser.cpp in Sources */, + 9A83D365AD1F37FA9C7030C4 /* matrix.cpp in Sources */, E3A4615870B139D29FE727C3 /* menucmn.cpp in Sources */, 171F09F8DD553FA5B4B3FAE4 /* modalhook.cpp in Sources */, BD49EC50CB363642BDBF25CA /* mousemanager.cpp in Sources */, @@ -8420,6 +8426,7 @@ CFF73578F04D357E83D1D831 /* lboxcmn.cpp in Sources */, 164010B26D363F5FA09785B7 /* listctrlcmn.cpp in Sources */, 2F7F5B9BBCD83D90B237A1A1 /* markupparser.cpp in Sources */, + 9A83D365AD1F37FA9C7030C3 /* matrix.cpp in Sources */, E3A4615870B139D29FE727C2 /* menucmn.cpp in Sources */, 171F09F8DD553FA5B4B3FAE3 /* modalhook.cpp in Sources */, BD49EC50CB363642BDBF25C9 /* mousemanager.cpp in Sources */, @@ -9650,6 +9657,7 @@ CFF73578F04D357E83D1D830 /* lboxcmn.cpp in Sources */, 164010B26D363F5FA09785B6 /* listctrlcmn.cpp in Sources */, 2F7F5B9BBCD83D90B237A1A0 /* markupparser.cpp in Sources */, + 9A83D365AD1F37FA9C7030C2 /* matrix.cpp in Sources */, E3A4615870B139D29FE727C1 /* menucmn.cpp in Sources */, 171F09F8DD553FA5B4B3FAE2 /* modalhook.cpp in Sources */, BD49EC50CB363642BDBF25C8 /* mousemanager.cpp in Sources */, diff --git a/build/osx/wxiphone.xcodeproj/project.pbxproj b/build/osx/wxiphone.xcodeproj/project.pbxproj index c13eba02f4..5f78a8530d 100644 --- a/build/osx/wxiphone.xcodeproj/project.pbxproj +++ b/build/osx/wxiphone.xcodeproj/project.pbxproj @@ -514,6 +514,7 @@ 99E7A46106C03484BA70D29E /* tif_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 5D2F8259CC99380CB8217DEF /* tif_unix.c */; }; 99F7D7BFBB543A04AB728375 /* m_hline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECA4A44BEC2F3AED8CF0C911 /* m_hline.cpp */; }; 9A178ED42D96329D8CBF9B89 /* tif_predict.c in Sources */ = {isa = PBXBuildFile; fileRef = 2FA01C426EAF38D3B9ED35AC /* tif_predict.c */; }; + 9A83D365AD1F37FA9C7030C2 /* matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF330EAACFA53877BE289896 /* matrix.cpp */; }; 9B3F9D04FB533D99B58BD519 /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 029486D6A2EC3DE0902A6A24 /* jfdctfst.c */; }; 9B6A35E706543CDAA6A5014A /* LexGui4Cli.cxx in Sources */ = {isa = PBXBuildFile; fileRef = FFB767BD2C7235F293F45796 /* LexGui4Cli.cxx */; }; 9B8E5690A6103FC1BDC6C47E /* pngread.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D6506AEA5A323B8735F126 /* pngread.c */; }; @@ -1663,6 +1664,7 @@ EEADAA811BBF3CBBB9E254FD /* xh_split.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_split.cpp; path = ../../src/xrc/xh_split.cpp; sourceTree = ""; }; EED7C691150139EFA35E8EBD /* utils_osx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = utils_osx.cpp; path = ../../src/osx/utils_osx.cpp; sourceTree = ""; }; EEE82083BFA430D5B58F8A04 /* regfree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regfree.c; path = ../../src/regex/regfree.c; sourceTree = ""; }; + EF330EAACFA53877BE289896 /* matrix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = matrix.cpp; path = ../../src/common/matrix.cpp; sourceTree = ""; }; F01DDE448E4C3983ACCE67FD /* appcmn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = appcmn.cpp; path = ../../src/common/appcmn.cpp; sourceTree = ""; }; F0905A1EBD653F6D82395602 /* xh_combo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xh_combo.cpp; path = ../../src/xrc/xh_combo.cpp; sourceTree = ""; }; F175D6E8E5723FC797701275 /* menucmn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = menucmn.cpp; path = ../../src/common/menucmn.cpp; sourceTree = ""; }; @@ -2119,6 +2121,7 @@ 9660AE8FEB7B3EDB857B9238 /* lboxcmn.cpp */, E1B1FBB2BCC43BA7A45E9438 /* listctrlcmn.cpp */, DA7F7633279936EFA0B9C5CF /* markupparser.cpp */, + EF330EAACFA53877BE289896 /* matrix.cpp */, F175D6E8E5723FC797701275 /* menucmn.cpp */, 58E7C516E2453A269280A404 /* modalhook.cpp */, D037EA567C253DEEA17E822B /* mousemanager.cpp */, @@ -3169,6 +3172,7 @@ CFF73578F04D357E83D1D830 /* lboxcmn.cpp in Sources */, 164010B26D363F5FA09785B6 /* listctrlcmn.cpp in Sources */, 2F7F5B9BBCD83D90B237A1A0 /* markupparser.cpp in Sources */, + 9A83D365AD1F37FA9C7030C2 /* matrix.cpp in Sources */, E3A4615870B139D29FE727C1 /* menucmn.cpp in Sources */, 171F09F8DD553FA5B4B3FAE2 /* modalhook.cpp in Sources */, BD49EC50CB363642BDBF25C8 /* mousemanager.cpp in Sources */, diff --git a/include/wx/matrix.h b/include/wx/matrix.h new file mode 100644 index 0000000000..b45473e3ee --- /dev/null +++ b/include/wx/matrix.h @@ -0,0 +1,234 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/matrix.h +// Purpose: wxTransformMatrix class. NOT YET USED +// Author: Chris Breeze, Julian Smart +// Modified by: Klaas Holwerda +// Created: 01/02/97 +// Copyright: (c) Julian Smart, Chris Breeze +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_MATRIXH__ +#define _WX_MATRIXH__ + +//! headerfiles="matrix.h wx/object.h" +#include "wx/object.h" +#include "wx/math.h" + +//! codefiles="matrix.cpp" + +// A simple 3x3 matrix. This may be replaced by a more general matrix +// class some day. +// +// Note: this is intended to be used in wxDC at some point to replace +// the current system of scaling/translation. It is not yet used. + +//:definition +// A 3x3 matrix to do 2D transformations. +// It can be used to map data to window coordinates, +// and also for manipulating your own data. +// For example drawing a picture (composed of several primitives) +// at a certain coordinate and angle within another parent picture. +// At all times m_isIdentity is set if the matrix itself is an Identity matrix. +// It is used where possible to optimize calculations. +class WXDLLIMPEXP_CORE wxTransformMatrix: public wxObject +{ +public: + wxTransformMatrix(); + wxTransformMatrix(const wxTransformMatrix& mat); + + //get the value in the matrix at col,row + //rows are horizontal (second index of m_matrix member) + //columns are vertical (first index of m_matrix member) + double GetValue(int col, int row) const; + + //set the value in the matrix at col,row + //rows are horizontal (second index of m_matrix member) + //columns are vertical (first index of m_matrix member) + void SetValue(int col, int row, double value); + + void operator = (const wxTransformMatrix& mat); + bool operator == (const wxTransformMatrix& mat) const; + bool operator != (const wxTransformMatrix& mat) const; + + //multiply every element by t + wxTransformMatrix& operator*=(const double& t); + //divide every element by t + wxTransformMatrix& operator/=(const double& t); + //add matrix m to this t + wxTransformMatrix& operator+=(const wxTransformMatrix& m); + //subtract matrix m from this + wxTransformMatrix& operator-=(const wxTransformMatrix& m); + //multiply matrix m with this + wxTransformMatrix& operator*=(const wxTransformMatrix& m); + + // constant operators + + //multiply every element by t and return result + wxTransformMatrix operator*(const double& t) const; + //divide this matrix by t and return result + wxTransformMatrix operator/(const double& t) const; + //add matrix m to this and return result + wxTransformMatrix operator+(const wxTransformMatrix& m) const; + //subtract matrix m from this and return result + wxTransformMatrix operator-(const wxTransformMatrix& m) const; + //multiply this by matrix m and return result + wxTransformMatrix operator*(const wxTransformMatrix& m) const; + wxTransformMatrix operator-() const; + + //rows are horizontal (second index of m_matrix member) + //columns are vertical (first index of m_matrix member) + double& operator()(int col, int row); + + //rows are horizontal (second index of m_matrix member) + //columns are vertical (first index of m_matrix member) + double operator()(int col, int row) const; + + // Invert matrix + bool Invert(); + + // Make into identity matrix + bool Identity(); + + // Is the matrix the identity matrix? + // Only returns a flag, which is set whenever an operation + // is done. + inline bool IsIdentity() const { return m_isIdentity; } + + // This does an actual check. + inline bool IsIdentity1() const ; + + //Scale by scale (isotropic scaling i.e. the same in x and y): + //!ex: + //!code: | scale 0 0 | + //!code: matrix' = | 0 scale 0 | x matrix + //!code: | 0 0 scale | + bool Scale(double scale); + + //Scale with center point and x/y scale + // + //!ex: + //!code: | xs 0 xc(1-xs) | + //!code: matrix' = | 0 ys yc(1-ys) | x matrix + //!code: | 0 0 1 | + wxTransformMatrix& Scale(const double &xs, const double &ys,const double &xc, const double &yc); + + // mirror a matrix in x, y + //!ex: + //!code: | -1 0 0 | + //!code: matrix' = | 0 -1 0 | x matrix + //!code: | 0 0 1 | + wxTransformMatrix& Mirror(bool x=true, bool y=false); + // Translate by dx, dy: + //!ex: + //!code: | 1 0 dx | + //!code: matrix' = | 0 1 dy | x matrix + //!code: | 0 0 1 | + bool Translate(double x, double y); + + // Rotate clockwise by the given number of degrees: + //!ex: + //!code: | cos sin 0 | + //!code: matrix' = | -sin cos 0 | x matrix + //!code: | 0 0 1 | + bool Rotate(double angle); + + //Rotate counter clockwise with point of rotation + // + //!ex: + //!code: | cos(r) -sin(r) x(1-cos(r))+y(sin(r)| + //!code: matrix' = | sin(r) cos(r) y(1-cos(r))-x(sin(r)| x matrix + //!code: | 0 0 1 | + wxTransformMatrix& Rotate(const double &r, const double &x, const double &y); + + // Transform X value from logical to device + inline double TransformX(double x) const; + + // Transform Y value from logical to device + inline double TransformY(double y) const; + + // Transform a point from logical to device coordinates + bool TransformPoint(double x, double y, double& tx, double& ty) const; + + // Transform a point from device to logical coordinates. + // Example of use: + // wxTransformMatrix mat = dc.GetTransformation(); + // mat.Invert(); + // mat.InverseTransformPoint(x, y, x1, y1); + // OR (shorthand:) + // dc.LogicalToDevice(x, y, x1, y1); + // The latter is slightly less efficient if we're doing several + // conversions, since the matrix is inverted several times. + // N.B. 'this' matrix is the inverse at this point + bool InverseTransformPoint(double x, double y, double& tx, double& ty) const; + + double Get_scaleX(); + double Get_scaleY(); + double GetRotation(); + void SetRotation(double rotation); + + +public: + double m_matrix[3][3]; + bool m_isIdentity; +}; + + +/* +Chris Breeze reported, that +some functions of wxTransformMatrix cannot work because it is not +known if he matrix has been inverted. Be careful when using it. +*/ + +// Transform X value from logical to device +// warning: this function can only be used for this purpose +// because no rotation is involved when mapping logical to device coordinates +// mirror and scaling for x and y will be part of the matrix +// if you have a matrix that is rotated, eg a shape containing a matrix to place +// it in the logical coordinate system, use TransformPoint +inline double wxTransformMatrix::TransformX(double x) const +{ + //normally like this, but since no rotation is involved (only mirror and scale) + //we can do without Y -> m_matrix[1]{0] is -sin(rotation angle) and therefore zero + //(x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0])) + return (m_isIdentity ? x : (x * m_matrix[0][0] + m_matrix[2][0])); +} + +// Transform Y value from logical to device +// warning: this function can only be used for this purpose +// because no rotation is involved when mapping logical to device coordinates +// mirror and scaling for x and y will be part of the matrix +// if you have a matrix that is rotated, eg a shape containing a matrix to place +// it in the logical coordinate system, use TransformPoint +inline double wxTransformMatrix::TransformY(double y) const +{ + //normally like this, but since no rotation is involved (only mirror and scale) + //we can do without X -> m_matrix[0]{1] is sin(rotation angle) and therefore zero + //(x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1])) + return (m_isIdentity ? y : (y * m_matrix[1][1] + m_matrix[2][1])); +} + + +// Is the matrix the identity matrix? +// Each operation checks whether the result is still the identity matrix and sets a flag. +inline bool wxTransformMatrix::IsIdentity1() const +{ + return + ( wxIsSameDouble(m_matrix[0][0], 1.0) && + wxIsSameDouble(m_matrix[1][1], 1.0) && + wxIsSameDouble(m_matrix[2][2], 1.0) && + wxIsSameDouble(m_matrix[1][0], 0.0) && + wxIsSameDouble(m_matrix[2][0], 0.0) && + wxIsSameDouble(m_matrix[0][1], 0.0) && + wxIsSameDouble(m_matrix[2][1], 0.0) && + wxIsSameDouble(m_matrix[0][2], 0.0) && + wxIsSameDouble(m_matrix[1][2], 0.0) ); +} + +// Calculates the determinant of a 2 x 2 matrix +inline double wxCalculateDet(double a11, double a21, double a12, double a22) +{ + return a11 * a22 - a12 * a21; +} + +#endif // _WX_MATRIXH__ diff --git a/src/common/matrix.cpp b/src/common/matrix.cpp new file mode 100644 index 0000000000..69ef92cc2d --- /dev/null +++ b/src/common/matrix.cpp @@ -0,0 +1,600 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/matrix.cpp +// Purpose: wxTransformMatrix class +// Author: Chris Breeze, Julian Smart +// Modified by: Klaas Holwerda +// Created: 01/02/97 +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// Note: this is intended to be used in wxDC at some point to replace +// the current system of scaling/translation. It is not yet used. + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/matrix.h" + +#ifndef WX_PRECOMP + #include "wx/math.h" +#endif + +static const double pi = M_PI; + +wxTransformMatrix::wxTransformMatrix() +{ + m_isIdentity = false; + + Identity(); +} + +wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat) + : wxObject() +{ + (*this) = mat; +} + +double wxTransformMatrix::GetValue(int col, int row) const +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return 0.0; + + return m_matrix[col][row]; +} + +void wxTransformMatrix::SetValue(int col, int row, double value) +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return; + + m_matrix[col][row] = value; + m_isIdentity = IsIdentity1(); +} + +void wxTransformMatrix::operator = (const wxTransformMatrix& mat) +{ + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + m_matrix[i][j] = mat.m_matrix[i][j]; + } + } + m_isIdentity = mat.m_isIdentity; +} + +bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const +{ + if (m_isIdentity && mat.m_isIdentity) + return true; + + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) ) + return false; + } + } + return true; +} + +bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const +{ + return (! ((*this) == mat)); +} + +double& wxTransformMatrix::operator()(int col, int row) +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return m_matrix[0][0]; + + return m_matrix[col][row]; +} + +double wxTransformMatrix::operator()(int col, int row) const +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return 0.0; + + return m_matrix[col][row]; +} + +// Invert matrix +bool wxTransformMatrix::Invert() +{ + double inverseMatrix[3][3]; + + // calculate the adjoint + inverseMatrix[0][0] = wxCalculateDet(m_matrix[1][1],m_matrix[2][1],m_matrix[1][2],m_matrix[2][2]); + inverseMatrix[0][1] = -wxCalculateDet(m_matrix[0][1],m_matrix[2][1],m_matrix[0][2],m_matrix[2][2]); + inverseMatrix[0][2] = wxCalculateDet(m_matrix[0][1],m_matrix[1][1],m_matrix[0][2],m_matrix[1][2]); + + inverseMatrix[1][0] = -wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][2],m_matrix[2][2]); + inverseMatrix[1][1] = wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][2],m_matrix[2][2]); + inverseMatrix[1][2] = -wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][2],m_matrix[1][2]); + + inverseMatrix[2][0] = wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][1],m_matrix[2][1]); + inverseMatrix[2][1] = -wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][1],m_matrix[2][1]); + inverseMatrix[2][2] = wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][1],m_matrix[1][1]); + + // now divide by the determinant + double det = m_matrix[0][0] * inverseMatrix[0][0] + m_matrix[0][1] * inverseMatrix[1][0] + m_matrix[0][2] * inverseMatrix[2][0]; + if ( wxIsNullDouble(det) ) + return false; + + inverseMatrix[0][0] /= det; inverseMatrix[1][0] /= det; inverseMatrix[2][0] /= det; + inverseMatrix[0][1] /= det; inverseMatrix[1][1] /= det; inverseMatrix[2][1] /= det; + inverseMatrix[0][2] /= det; inverseMatrix[1][2] /= det; inverseMatrix[2][2] /= det; + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + m_matrix[i][j] = inverseMatrix[i][j]; + } + } + m_isIdentity = IsIdentity1(); + return true; +} + +// Make into identity matrix +bool wxTransformMatrix::Identity() +{ + m_matrix[0][0] = m_matrix[1][1] = m_matrix[2][2] = 1.0; + m_matrix[1][0] = m_matrix[2][0] = m_matrix[0][1] = m_matrix[2][1] = m_matrix[0][2] = m_matrix[1][2] = 0.0; + m_isIdentity = true; + + return true; +} + +// Scale by scale (isotropic scaling i.e. the same in x and y): +// | scale 0 0 | +// matrix' = | 0 scale 0 | x matrix +// | 0 0 scale | +// +bool wxTransformMatrix::Scale(double scale) +{ + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + m_matrix[i][j] *= scale; + } + } + m_isIdentity = IsIdentity1(); + + return true; +} + + +// scale a matrix in 2D +// +// xs 0 xc(1-xs) +// 0 ys yc(1-ys) +// 0 0 1 +// +wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc) +{ + double r00,r10,r20,r01,r11,r21; + + if (m_isIdentity) + { + double tx = xc*(1-xs); + double ty = yc*(1-ys); + r00 = xs; + r10 = 0; + r20 = tx; + r01 = 0; + r11 = ys; + r21 = ty; + } + else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) ) + { + double tx = xc*(1-xs); + double ty = yc*(1-ys); + r00 = xs * m_matrix[0][0]; + r10 = xs * m_matrix[1][0]; + r20 = xs * m_matrix[2][0] + tx; + r01 = ys * m_matrix[0][1]; + r11 = ys * m_matrix[1][1]; + r21 = ys * m_matrix[2][1] + ty; + } + else + { + r00 = xs * m_matrix[0][0]; + r10 = xs * m_matrix[1][0]; + r20 = xs * m_matrix[2][0]; + r01 = ys * m_matrix[0][1]; + r11 = ys * m_matrix[1][1]; + r21 = ys * m_matrix[2][1]; + } + + m_matrix[0][0] = r00; + m_matrix[1][0] = r10; + m_matrix[2][0] = r20; + m_matrix[0][1] = r01; + m_matrix[1][1] = r11; + m_matrix[2][1] = r21; + +/* or like this + // first translate to origin O + (*this).Translate(-x_cen, -y_cen); + + // now do the scaling + wxTransformMatrix scale; + scale.m_matrix[0][0] = x_fac; + scale.m_matrix[1][1] = y_fac; + scale.m_isIdentity = IsIdentity1(); + + *this = scale * (*this); + + // translate back from origin to x_cen, y_cen + (*this).Translate(x_cen, y_cen); +*/ + + m_isIdentity = IsIdentity1(); + + return *this; +} + + +// mirror a matrix in x, y +// +// -1 0 0 Y-mirror +// 0 -1 0 X-mirror +// 0 0 -1 Z-mirror +wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y) +{ + wxTransformMatrix temp; + if (x) + { + temp.m_matrix[1][1] = -1; + temp.m_isIdentity=false; + } + if (y) + { + temp.m_matrix[0][0] = -1; + temp.m_isIdentity=false; + } + + *this = temp * (*this); + m_isIdentity = IsIdentity1(); + return *this; +} + +// Translate by dx, dy: +// | 1 0 dx | +// matrix' = | 0 1 dy | x matrix +// | 0 0 1 | +// +bool wxTransformMatrix::Translate(double dx, double dy) +{ + int i; + for (i = 0; i < 3; i++) + m_matrix[i][0] += dx * m_matrix[i][2]; + for (i = 0; i < 3; i++) + m_matrix[i][1] += dy * m_matrix[i][2]; + + m_isIdentity = IsIdentity1(); + + return true; +} + +// Rotate clockwise by the given number of degrees: +// | cos sin 0 | +// matrix' = | -sin cos 0 | x matrix +// | 0 0 1 | +bool wxTransformMatrix::Rotate(double degrees) +{ + Rotate(-degrees,0,0); + return true; +} + +// counter clockwise rotate around a point +// +// cos(r) -sin(r) x(1-cos(r))+y(sin(r) +// sin(r) cos(r) y(1-cos(r))-x(sin(r) +// 0 0 1 +wxTransformMatrix& wxTransformMatrix::Rotate(const double °rees, const double &x, const double &y) +{ + double angle = degrees * pi / 180.0; + double c = cos(angle); + double s = sin(angle); + double r00,r10,r20,r01,r11,r21; + + if (m_isIdentity) + { + double tx = x*(1-c)+y*s; + double ty = y*(1-c)-x*s; + r00 = c ; + r10 = -s; + r20 = tx; + r01 = s; + r11 = c; + r21 = ty; + } + else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) ) + { + double tx = x*(1-c)+y*s; + double ty = y*(1-c)-x*s; + r00 = c * m_matrix[0][0] - s * m_matrix[0][1] + tx * m_matrix[0][2]; + r10 = c * m_matrix[1][0] - s * m_matrix[1][1] + tx * m_matrix[1][2]; + r20 = c * m_matrix[2][0] - s * m_matrix[2][1] + tx;// * m_matrix[2][2]; + r01 = c * m_matrix[0][1] + s * m_matrix[0][0] + ty * m_matrix[0][2]; + r11 = c * m_matrix[1][1] + s * m_matrix[1][0] + ty * m_matrix[1][2]; + r21 = c * m_matrix[2][1] + s * m_matrix[2][0] + ty;// * m_matrix[2][2]; + } + else + { + r00 = c * m_matrix[0][0] - s * m_matrix[0][1]; + r10 = c * m_matrix[1][0] - s * m_matrix[1][1]; + r20 = c * m_matrix[2][0] - s * m_matrix[2][1]; + r01 = c * m_matrix[0][1] + s * m_matrix[0][0]; + r11 = c * m_matrix[1][1] + s * m_matrix[1][0]; + r21 = c * m_matrix[2][1] + s * m_matrix[2][0]; + } + + m_matrix[0][0] = r00; + m_matrix[1][0] = r10; + m_matrix[2][0] = r20; + m_matrix[0][1] = r01; + m_matrix[1][1] = r11; + m_matrix[2][1] = r21; + +/* or like this + wxTransformMatrix rotate; + rotate.m_matrix[2][0] = tx; + rotate.m_matrix[2][1] = ty; + + rotate.m_matrix[0][0] = c; + rotate.m_matrix[0][1] = s; + + rotate.m_matrix[1][0] = -s; + rotate.m_matrix[1][1] = c; + + rotate.m_isIdentity=false; + *this = rotate * (*this); +*/ + m_isIdentity = IsIdentity1(); + + return *this; +} + +// Transform a point from logical to device coordinates +bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const +{ + if (IsIdentity()) + { + tx = x; ty = y; return true; + } + + tx = x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]; + ty = x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]; + + return true; +} + +// Transform a point from device to logical coordinates. + +// Example of use: +// wxTransformMatrix mat = dc.GetTransformation(); +// mat.Invert(); +// mat.InverseTransformPoint(x, y, x1, y1); +// OR (shorthand:) +// dc.LogicalToDevice(x, y, x1, y1); +// The latter is slightly less efficient if we're doing several +// conversions, since the matrix is inverted several times. +bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const +{ + if (IsIdentity()) + { + tx = x; + ty = y; + return true; + } + + const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2]; + if ( wxIsNullDouble(z) ) + return false; + + tx = x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; + ty = x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; + return true; +} + +wxTransformMatrix& wxTransformMatrix::operator*=(const double& t) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j]*= t; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator/=(const double& t) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j]/= t; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j] += mat.m_matrix[i][j]; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j] -= mat.m_matrix[i][j]; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat) +{ + + if (mat.m_isIdentity) + return *this; + if (m_isIdentity) + { + *this = mat; + return *this; + } + else + { + wxTransformMatrix result; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + double sum = 0; + for (int k = 0; k < 3; k++) + sum += m_matrix[k][i] * mat.m_matrix[j][k]; + result.m_matrix[j][i] = sum; + } + } + *this = result; + } + + m_isIdentity = IsIdentity1(); + return *this; +} + + +// constant operators +wxTransformMatrix wxTransformMatrix::operator*(const double& t) const +{ + wxTransformMatrix result = *this; + result *= t; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +wxTransformMatrix wxTransformMatrix::operator/(const double& t) const +{ + wxTransformMatrix result = *this; +// wxASSERT(t!=0); + result /= t; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const +{ + wxTransformMatrix result = *this; + result += m; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const +{ + wxTransformMatrix result = *this; + result -= m; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + + +wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const +{ + wxTransformMatrix result = *this; + result *= m; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + + +wxTransformMatrix wxTransformMatrix::operator-() const +{ + wxTransformMatrix result = *this; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + result.m_matrix[i][j] = -(this->m_matrix[i][j]); + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +static double CheckInt(double getal) +{ + // check if the number is very close to an integer + if ( (ceil(getal) - getal) < 0.0001) + return ceil(getal); + + else if ( (getal - floor(getal)) < 0.0001) + return floor(getal); + + return getal; + +} + +double wxTransformMatrix::Get_scaleX() +{ + double scale_factor; + double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); + if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) + scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi); + else + scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! + + scale_factor = CheckInt(scale_factor); + if (scale_factor < 0) + scale_factor = -scale_factor; + + return scale_factor; +} + +double wxTransformMatrix::Get_scaleY() +{ + double scale_factor; + double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); + if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) + scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi); + else + scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! + + scale_factor = CheckInt(scale_factor); + if (scale_factor < 0) + + scale_factor = -scale_factor; + + return scale_factor; + +} + +double wxTransformMatrix::GetRotation() +{ + double temp1 = GetValue(0,0); // for angle calculation + double temp2 = GetValue(0,1); // + + // Rotation + double rot_angle = atan2(temp2,temp1)*180/pi; + + rot_angle = CheckInt(rot_angle); + return rot_angle; +} + +void wxTransformMatrix::SetRotation(double rotation) +{ + double x=GetValue(2,0); + double y=GetValue(2,1); + Rotate(-GetRotation(), x, y); + Rotate(rotation, x, y); +} diff --git a/tests/allheaders.h b/tests/allheaders.h index 4915ad7efb..7da480582a 100644 --- a/tests/allheaders.h +++ b/tests/allheaders.h @@ -217,6 +217,7 @@ #include #include #include +#include #include #include #include From 2388f5d33fa2dac91cfaa205ed9bd797ed936fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Mon, 5 Oct 2020 16:44:23 +0200 Subject: [PATCH 098/105] Don't crash if WXPREFIX env. variable is set Change wxGetInstallPrefix() to return a string instead of const wxChar*. The latter was incorrectly obtained from a temporary string if WXPREFIX was set. While it's possible to fix in a backward compatible manner without changing the function's signature, it's not worth the effort for something pretty obscure and used mostly internally. --- docs/changes.txt | 2 ++ include/wx/utils.h | 2 +- src/common/utilscmn.cpp | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index a5196548aa..ba14312ee6 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -105,6 +105,8 @@ Changes in behaviour not resulting in compilation errors - wxFileDialog::GetPath() and wxFileDialog::GetFilename() now assert and return an empty string if called on dialogs with the wxFD_MULTIPLE style. +- wxGetInstallPrefix() now returns wxString. + Changes in behaviour which may result in build errors ----------------------------------------------------- diff --git a/include/wx/utils.h b/include/wx/utils.h index c6d35299c2..3f4aea8daf 100644 --- a/include/wx/utils.h +++ b/include/wx/utils.h @@ -162,7 +162,7 @@ WXDLLIMPEXP_BASE wxLinuxDistributionInfo wxGetLinuxDistributionInfo(); WXDLLIMPEXP_BASE wxString wxNow(); // Return path where wxWidgets is installed (mostly useful in Unices) -WXDLLIMPEXP_BASE const wxChar *wxGetInstallPrefix(); +WXDLLIMPEXP_BASE wxString wxGetInstallPrefix(); // Return path to wxWin data (/usr/share/wx/%{version}) (Unices) WXDLLIMPEXP_BASE wxString wxGetDataDir(); diff --git a/src/common/utilscmn.cpp b/src/common/utilscmn.cpp index 05b6fa002f..bcfee48b33 100644 --- a/src/common/utilscmn.cpp +++ b/src/common/utilscmn.cpp @@ -182,12 +182,12 @@ void wxUsleep(unsigned long milliseconds) } #endif -const wxChar *wxGetInstallPrefix() +wxString wxGetInstallPrefix() { wxString prefix; if ( wxGetEnv(wxT("WXPREFIX"), &prefix) ) - return prefix.c_str(); + return prefix; #ifdef wxINSTALL_PREFIX return wxT(wxINSTALL_PREFIX); From b355e001491b60fd8add1002966fd3f54199b0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Mon, 5 Oct 2020 16:41:26 +0200 Subject: [PATCH 099/105] Only warn about missing WebKit extension when used Don't log failure to load the extension during initialization, because it isn't needed for many uses of wxWebView. Instead, only report the failure at the time when functionality depending on it is used. Also use g_warning() for logging consistently with other failures in this file. This doesn't interrupt the user, yet shows the problem highly visibly in the console. --- include/wx/gtk/webview_webkit.h | 1 + src/gtk/webview_webkit2.cpp | 70 ++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/include/wx/gtk/webview_webkit.h b/include/wx/gtk/webview_webkit.h index acabc88e94..fccdfcd8d8 100644 --- a/include/wx/gtk/webview_webkit.h +++ b/include/wx/gtk/webview_webkit.h @@ -162,6 +162,7 @@ private: #if wxUSE_WEBVIEW_WEBKIT2 bool CanExecuteEditingCommand(const gchar* command) const; void SetupWebExtensionServer(); + GDBusProxy *GetExtensionProxy() const; bool RunScriptSync(const wxString& javascript, wxString* output = NULL); #endif diff --git a/src/gtk/webview_webkit2.cpp b/src/gtk/webview_webkit2.cpp index 72351dd8e5..43df84702b 100644 --- a/src/gtk/webview_webkit2.cpp +++ b/src/gtk/webview_webkit2.cpp @@ -399,6 +399,14 @@ static bool CheckDirectoryForWebExt(const wxString& dirname) return false; } +static wxString GetStandardWebExtensionsDir() +{ + wxString dir = wxDynamicLibrary::GetPluginsDirectory(); + if ( !dir.empty() ) + dir += "/web-extensions"; + return dir; +} + static void wxgtk_initialize_web_extensions(WebKitWebContext *context, GDBusServer *dbusServer) @@ -409,40 +417,23 @@ wxgtk_initialize_web_extensions(WebKitWebContext *context, // The first value is the location in which the extension is supposed to be // normally installed, while the other three are used as fallbacks to allow // running the tests and sample using wxWebView before installing it. - - wxString normalLocation = wxDynamicLibrary::GetPluginsDirectory(); - if ( !normalLocation.empty() ) - normalLocation += "/web-extensions"; - wxString const directories[] = { - normalLocation, + GetStandardWebExtensionsDir(), "..", "../..", "lib", }; - wxString dir; for ( size_t n = 0; n < WXSIZEOF(directories); ++n ) { if ( !directories[n].empty() && CheckDirectoryForWebExt(directories[n]) ) { - dir = directories[n]; + webkit_web_context_set_web_extensions_directory(context, directories[n].utf8_str()); break; } } - if ( !dir.empty() ) - { - webkit_web_context_set_web_extensions_directory(context, dir.utf8_str()); - } - else - { - wxLogWarning(_("Web extension not found in \"%s\", " - "some wxWebView functionality will be not available"), - directories[0]); - } - webkit_web_context_set_web_extensions_initialization_user_data(context, user_data); } @@ -1025,10 +1016,11 @@ bool wxWebViewWebKit::IsEditable() const void wxWebViewWebKit::DeleteSelection() { - if (m_extension) + GDBusProxy *extension = GetExtensionProxy(); + if (extension) { guint64 page_id = webkit_web_view_get_page_id(m_web_view); - GVariant *retval = g_dbus_proxy_call_sync(m_extension, + GVariant *retval = g_dbus_proxy_call_sync(extension, "DeleteSelection", g_variant_new("(t)", page_id), G_DBUS_CALL_FLAGS_NONE, -1, @@ -1042,10 +1034,11 @@ void wxWebViewWebKit::DeleteSelection() bool wxWebViewWebKit::HasSelection() const { - if (m_extension) + GDBusProxy *extension = GetExtensionProxy(); + if (extension) { guint64 page_id = webkit_web_view_get_page_id(m_web_view); - GVariant *retval = g_dbus_proxy_call_sync(m_extension, + GVariant *retval = g_dbus_proxy_call_sync(extension, "HasSelection", g_variant_new("(t)", page_id), G_DBUS_CALL_FLAGS_NONE, -1, @@ -1069,10 +1062,11 @@ void wxWebViewWebKit::SelectAll() wxString wxWebViewWebKit::GetSelectedText() const { - if (m_extension) + GDBusProxy *extension = GetExtensionProxy(); + if (extension) { guint64 page_id = webkit_web_view_get_page_id(m_web_view); - GVariant *retval = g_dbus_proxy_call_sync(m_extension, + GVariant *retval = g_dbus_proxy_call_sync(extension, "GetSelectedText", g_variant_new("(t)", page_id), G_DBUS_CALL_FLAGS_NONE, -1, @@ -1090,10 +1084,11 @@ wxString wxWebViewWebKit::GetSelectedText() const wxString wxWebViewWebKit::GetSelectedSource() const { - if (m_extension) + GDBusProxy *extension = GetExtensionProxy(); + if (extension) { guint64 page_id = webkit_web_view_get_page_id(m_web_view); - GVariant *retval = g_dbus_proxy_call_sync(m_extension, + GVariant *retval = g_dbus_proxy_call_sync(extension, "GetSelectedSource", g_variant_new("(t)", page_id), G_DBUS_CALL_FLAGS_NONE, -1, @@ -1111,10 +1106,11 @@ wxString wxWebViewWebKit::GetSelectedSource() const void wxWebViewWebKit::ClearSelection() { - if (m_extension) + GDBusProxy *extension = GetExtensionProxy(); + if (extension) { guint64 page_id = webkit_web_view_get_page_id(m_web_view); - GVariant *retval = g_dbus_proxy_call_sync(m_extension, + GVariant *retval = g_dbus_proxy_call_sync(extension, "ClearSelection", g_variant_new("(t)", page_id), G_DBUS_CALL_FLAGS_NONE, -1, @@ -1128,10 +1124,11 @@ void wxWebViewWebKit::ClearSelection() wxString wxWebViewWebKit::GetPageText() const { - if (m_extension) + GDBusProxy *extension = GetExtensionProxy(); + if (extension) { guint64 page_id = webkit_web_view_get_page_id(m_web_view); - GVariant *retval = g_dbus_proxy_call_sync(m_extension, + GVariant *retval = g_dbus_proxy_call_sync(extension, "GetPageText", g_variant_new("(t)", page_id), G_DBUS_CALL_FLAGS_NONE, -1, @@ -1415,4 +1412,15 @@ void wxWebViewWebKit::SetupWebExtensionServer() g_object_unref(observer); } +GDBusProxy *wxWebViewWebKit::GetExtensionProxy() const +{ + if (!m_extension) + { + g_warning("Web extension not found in \"%s\", " + "some wxWebView functionality will be not available", + (const char*)GetStandardWebExtensionsDir().utf8_str()); + } + return m_extension; +} + #endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT2 From 8756ff4320d6636d81c30c24c7afaee822be40fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Thu, 8 Oct 2020 19:41:30 +0200 Subject: [PATCH 100/105] Don't load webkit extensions from CWD-relative paths wxgtk_initialize_web_extensions() tries to find extensions in the location where "make install" puts them. If that fails, either because wx wasn't installed yet, or it was deployed (e.g. in static build) without them, it looks into additional places - paths relative to CWD. This is to faciliate running wx samples and tests, but by being enabled in release builds too, it allowed loading unexpected executable code from untrusted locations. For example, on typical desktops, one could put malicious .so files into $HOME/lib to have them loaded by wxWebView-using applications. Address this by making the helper paths relative to the executable's location, not working directory. --- src/gtk/webview_webkit2.cpp | 44 ++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/gtk/webview_webkit2.cpp b/src/gtk/webview_webkit2.cpp index 43df84702b..c507d4b64a 100644 --- a/src/gtk/webview_webkit2.cpp +++ b/src/gtk/webview_webkit2.cpp @@ -14,6 +14,7 @@ #include "wx/dir.h" #include "wx/dynlib.h" #include "wx/filename.h" +#include "wx/stdpaths.h" #include "wx/stockitem.h" #include "wx/gtk/webview_webkit.h" #include "wx/gtk/control.h" @@ -399,6 +400,15 @@ static bool CheckDirectoryForWebExt(const wxString& dirname) return false; } +static bool TrySetWebExtensionsDirectory(WebKitWebContext *context, const wxString& dir) +{ + if (dir.empty() || !CheckDirectoryForWebExt(dir)) + return false; + + webkit_web_context_set_web_extensions_directory(context, dir.utf8_str()); + return true; +} + static wxString GetStandardWebExtensionsDir() { wxString dir = wxDynamicLibrary::GetPluginsDirectory(); @@ -414,23 +424,27 @@ wxgtk_initialize_web_extensions(WebKitWebContext *context, const char *address = g_dbus_server_get_client_address(dbusServer); GVariant *user_data = g_variant_new("(s)", address); - // The first value is the location in which the extension is supposed to be - // normally installed, while the other three are used as fallbacks to allow - // running the tests and sample using wxWebView before installing it. - wxString const directories[] = + // Try to setup extension loading from the location it is supposed to be + // normally installed in. + if ( !TrySetWebExtensionsDirectory(context, GetStandardWebExtensionsDir()) ) { - GetStandardWebExtensionsDir(), - "..", - "../..", - "lib", - }; - - for ( size_t n = 0; n < WXSIZEOF(directories); ++n ) - { - if ( !directories[n].empty() && CheckDirectoryForWebExt(directories[n]) ) + // These relative locations are used as fallbacks to allow running + // the tests and sample using wxWebView before installing it. + wxString exepath = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath(); + if ( !exepath.empty() ) { - webkit_web_context_set_web_extensions_directory(context, directories[n].utf8_str()); - break; + wxString const directories[] = + { + exepath + "/..", + exepath + "/../..", + exepath + "/lib", + }; + + for ( size_t n = 0; n < WXSIZEOF(directories); ++n ) + { + if ( !TrySetWebExtensionsDirectory(context, directories[n]) ) + break; + } } } From 952e5f32cd877de57e5d0f282b920537a83225d0 Mon Sep 17 00:00:00 2001 From: PB Date: Wed, 7 Oct 2020 18:18:55 +0200 Subject: [PATCH 101/105] Fix generation of extraneous wxEVT_SLIDER events in wxMSW Don't send the event when it's redundant, i.e. doesn't really notify about the change in the slider value. Also add a test case for wxEVT_SLIDER and show these events in the widgets sample. Closes https://github.com/wxWidgets/wxWidgets/pull/2080 Closes #18929. --- samples/widgets/slider.cpp | 10 ++++++++++ src/msw/slider.cpp | 23 ++++++++++++++++++----- tests/controls/slidertest.cpp | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/samples/widgets/slider.cpp b/samples/widgets/slider.cpp index 32bf2fad60..4fbda64f11 100644 --- a/samples/widgets/slider.cpp +++ b/samples/widgets/slider.cpp @@ -120,6 +120,7 @@ protected: void OnCheckOrRadioBox(wxCommandEvent& event); void OnSlider(wxScrollEvent& event); + void OnSlider(wxCommandEvent& event); void OnUpdateUIValueButton(wxUpdateUIEvent& event); void OnUpdateUIMinMaxButton(wxUpdateUIEvent& event); @@ -230,6 +231,7 @@ wxBEGIN_EVENT_TABLE(SliderWidgetsPage, WidgetsPage) EVT_UPDATE_UI(SliderPage_CurValueText, SliderWidgetsPage::OnUpdateUICurValueText) EVT_COMMAND_SCROLL(SliderPage_Slider, SliderWidgetsPage::OnSlider) + EVT_SLIDER(SliderPage_Slider, SliderWidgetsPage::OnSlider) EVT_CHECKBOX(wxID_ANY, SliderWidgetsPage::OnCheckOrRadioBox) EVT_RADIOBOX(wxID_ANY, SliderWidgetsPage::OnCheckOrRadioBox) @@ -845,4 +847,12 @@ void SliderWidgetsPage::OnSlider(wxScrollEvent& event) event.GetInt()); } +void SliderWidgetsPage::OnSlider(wxCommandEvent& event) +{ + static int s_numSliderEvents = 0; + + wxLogMessage("Slider event #%d: wxEVT_SLIDER (value = %d)", + s_numSliderEvents++, event.GetInt()); +} + #endif // wxUSE_SLIDER diff --git a/src/msw/slider.cpp b/src/msw/slider.cpp index d859ea5d55..3cb247965d 100644 --- a/src/msw/slider.cpp +++ b/src/msw/slider.cpp @@ -313,15 +313,28 @@ bool wxSlider::MSWOnScroll(int WXUNUSED(orientation), SetValue(newPos); wxScrollEvent event(scrollEvent, m_windowId); + bool processed = false; + event.SetPosition(newPos); event.SetEventObject( this ); - HandleWindowEvent(event); + processed = HandleWindowEvent(event); - wxCommandEvent cevent( wxEVT_SLIDER, GetId() ); - cevent.SetInt( newPos ); - cevent.SetEventObject( this ); + // Do not generate wxEVT_SLIDER when the native scroll message + // parameter is SB_ENDSCROLL, which always follows only after + // another scroll message which already changed the slider value. + // Therefore, sending wxEVT_SLIDER after SB_ENDSCROLL + // would result in two wxEVT_SLIDER events with the same value. + if ( wParam != SB_ENDSCROLL ) + { + wxCommandEvent cevent( wxEVT_SLIDER, GetId() ); - return HandleWindowEvent( cevent ); + cevent.SetInt( newPos ); + cevent.SetEventObject( this ); + + processed = HandleWindowEvent( cevent ); + } + + return processed; } void wxSlider::Command (wxCommandEvent & event) diff --git a/tests/controls/slidertest.cpp b/tests/controls/slidertest.cpp index 9ecc97327c..aac59a2bca 100644 --- a/tests/controls/slidertest.cpp +++ b/tests/controls/slidertest.cpp @@ -35,6 +35,7 @@ private: #ifndef __WXOSX__ WXUISIM_TEST( PageUpDown ); WXUISIM_TEST( LineUpDown ); + WXUISIM_TEST( EvtSlider ); WXUISIM_TEST( LinePageSize ); #endif CPPUNIT_TEST( Value ); @@ -47,6 +48,7 @@ private: void PageUpDown(); void LineUpDown(); + void EvtSlider(); void LinePageSize(); void Value(); void Range(); @@ -125,6 +127,24 @@ void SliderTestCase::LineUpDown() #endif } +void SliderTestCase::EvtSlider() +{ +#if wxUSE_UIACTIONSIMULATOR + EventCounter slider(m_slider, wxEVT_SLIDER); + + wxUIActionSimulator sim; + wxYield(); + m_slider->SetFocus(); + + sim.Char(WXK_UP); + sim.Char(WXK_DOWN); + + wxYield(); + + CPPUNIT_ASSERT_EQUAL(2, slider.GetCount()); +#endif +} + void SliderTestCase::LinePageSize() { #if wxUSE_UIACTIONSIMULATOR From 80a3cd2db9cd24fad5b830244eab837261abc027 Mon Sep 17 00:00:00 2001 From: Artur Sochirca Date: Thu, 8 Oct 2020 18:56:21 +0300 Subject: [PATCH 102/105] Avoid using non-ASCII key codes in key up/down events in wxOSX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generating such events could result in mishandling some key presses as special keys, e.g. the Turkish "ş" characters was mistakenly processed as F12 because F12 corresponds to its Unicode character code (U+015F). Avoid this by only setting wxKeyEvent::m_keyCode for printable characters (while still making the actual key available in m_uniChar). This makes wxOSX consistent with wxGTK and documented behaviour. Closes https://github.com/wxWidgets/wxWidgets/pull/2081 --- src/osx/cocoa/window.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 813bb1face..7f26b8585e 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -518,7 +518,7 @@ void wxWidgetCocoaImpl::SetupKeyEvent(wxKeyEvent &wxevent , NSEvent * nsEvent, N } } - if ( !keyval ) + if ( !keyval && aunichar < 256 ) // only for ASCII characters { if ( wxevent.GetEventType() == wxEVT_KEY_UP || wxevent.GetEventType() == wxEVT_KEY_DOWN ) keyval = wxToupper( aunichar ) ; From fedc80eee3c449cec894f3bdfacd8ef01e41f71b Mon Sep 17 00:00:00 2001 From: ali kettab Date: Sun, 6 Sep 2020 00:53:45 +0100 Subject: [PATCH 103/105] Improve selection and focus events generation in wxGenericLisCtrl Avoid sending spurious wxEVT_LIST_ITEM_{FOCUSED, SELECTED, DESELECTED} events and make the generic version consistent with the behaviour of the native wxMSW one. Also add/extend the tests and slightly improve the sample. Closes https://github.com/wxWidgets/wxWidgets/pull/2044 --- include/wx/generic/private/listctrl.h | 51 ++++- samples/listctrl/listtest.cpp | 59 ++++-- src/generic/listctrl.cpp | 286 +++++++++++++++++++------- tests/controls/listbasetest.cpp | 125 ++++++++++- tests/controls/listbasetest.h | 2 + tests/controls/listviewtest.cpp | 8 +- 6 files changed, 432 insertions(+), 99 deletions(-) diff --git a/include/wx/generic/private/listctrl.h b/include/wx/generic/private/listctrl.h index c5741b6b13..4087889098 100644 --- a/include/wx/generic/private/listctrl.h +++ b/include/wx/generic/private/listctrl.h @@ -519,14 +519,26 @@ public: // all these functions only do something if the line is currently visible + // Make sure that _line_ is the only item highlighted in the control. + // _oldLine_ is the old focused item. + void HighlightOnly( size_t line, size_t oldLine = (size_t)-1 ); + + // In multiple selection mode, instead of sending one notification per item + // (which is too slow if a lot of items are selected) we send only one notification + // for all of them which is the wxMSW behaviour. Currently done for virtual + // list controls and for deselection only. + enum SendEvent { SendEvent_None, SendEvent_Normal }; + // change the line "selected" state, return true if it really changed - bool HighlightLine( size_t line, bool highlight = true); + bool HighlightLine( size_t line, bool highlight = true, + SendEvent sendEvent = SendEvent_Normal ); // as HighlightLine() but do it for the range of lines: this is incredibly // more efficient for virtual list controls! // // NB: unlike HighlightLine() this one does refresh the lines on screen - void HighlightLines( size_t lineFrom, size_t lineTo, bool on = true ); + void HighlightLines( size_t lineFrom, size_t lineTo, bool on = true, + SendEvent sendEvent = SendEvent_Normal ); // toggle the line state and refresh it void ReverseHighlight( size_t line ) @@ -753,6 +765,16 @@ public: return m_hasFocus; } + void UpdateSelectionCount(bool selected) + { + wxASSERT_MSG( !IsVirtual(), "Can be called for non virtual lists only" ); + + if ( IsSingleSel() ) + return; + + selected ? ++m_selCount : --m_selCount; + } + protected: // the array of all line objects for a non virtual list control (for the // virtual list control we only ever use m_lines[0]) @@ -803,11 +825,18 @@ protected: m_lineBeforeLastClicked, m_lineSelectSingleOnUp; + // Multiple selection extends from the anchor. Not used in single-selection mode. + size_t m_anchor; + bool m_hasCheckBoxes; protected: wxWindow *GetMainWindowOfCompositeControl() wxOVERRIDE { return GetParent(); } + // the total count of items selected in a non virtual list control with + // multiple selections (always 0 otherwise) + size_t m_selCount; + // the total count of items in a virtual list control size_t m_countVirt; @@ -858,6 +887,24 @@ private: // initialize the current item if needed void UpdateCurrent(); + // change the current (== focused) item, without sending any event + // return true if m_current really changed. + bool ChangeCurrentWithoutEvent(size_t current); + + // Trying to activate the current item from keyboard is only possible + // if it is actually selected. We don't send wxEVT_LIST_ITEM_ACTIVATED + // event if it is not, and wxEVT_LIST_KEY_DOWN event should carry -1 + // in this case, as the wxMSW implementation does. + bool ShouldSendEventForCurrent() const + { + return HasCurrent() && IsHighlighted(m_current); + } + + // For multiple selection mode. + // Change the selected range from [anchor, oldCurrent] to [anchor, newCurrent] + // without generating unnecessary wxEVT_LIST_ITEM_{DE}SELECTED events. + void ExtendSelection(size_t oldCurrent, size_t newCurrent); + // delete all items but don't refresh: called from dtor void DoDeleteAllItems(); diff --git a/samples/listctrl/listtest.cpp b/samples/listctrl/listtest.cpp index 2218622b4e..4ef123fa73 100644 --- a/samples/listctrl/listtest.cpp +++ b/samples/listctrl/listtest.cpp @@ -564,6 +564,15 @@ void MyFrame::InitWithReportItems() itemCol.SetAlign(wxLIST_FORMAT_RIGHT); m_listCtrl->InsertColumn(2, itemCol); + if ( m_numListItems <= 0 ) + { + m_listCtrl->SetColumnWidth( 0, 100 ); + m_listCtrl->SetColumnWidth( 1, wxLIST_AUTOSIZE ); + m_listCtrl->SetColumnWidth( 2, wxLIST_AUTOSIZE_USEHEADER ); + + return; + } + // to speed up inserting we hide the control temporarily m_listCtrl->Hide(); @@ -584,25 +593,38 @@ void MyFrame::InitWithReportItems() item.SetTextColour(*wxRED); m_listCtrl->SetItem( item ); - item.m_itemId = 2; - item.SetTextColour(*wxGREEN); - m_listCtrl->SetItem( item ); - item.m_itemId = 4; - item.SetTextColour(*wxLIGHT_GREY); - item.SetFont(*wxITALIC_FONT); - item.SetBackgroundColour(*wxRED); - m_listCtrl->SetItem( item ); + if ( m_numListItems > 2 ) + { + item.m_itemId = 2; + item.SetTextColour(*wxGREEN); + m_listCtrl->SetItem( item ); + } + + if ( m_numListItems > 4 ) + { + item.m_itemId = 4; + item.SetTextColour(*wxLIGHT_GREY); + item.SetFont(*wxITALIC_FONT); + item.SetBackgroundColour(*wxRED); + m_listCtrl->SetItem( item ); + } m_listCtrl->SetTextColour(*wxBLUE); - // Set images in columns - m_listCtrl->SetItemColumnImage(1, 1, 0); + if ( m_numListItems > 1 ) + { + // Set images in columns + m_listCtrl->SetItemColumnImage(1, 1, 0); + } - wxListItem info; - info.SetImage(0); - info.SetId(3); - info.SetColumn(2); - m_listCtrl->SetItem(info); + if ( m_numListItems > 3 ) + { + wxListItem info; + info.SetImage(0); + info.SetId(3); + info.SetColumn(2); + m_listCtrl->SetItem(info); + } // test SetItemFont too m_listCtrl->SetItemFont(0, *wxITALIC_FONT); @@ -1073,6 +1095,11 @@ void MyListCtrl::OnColClick(wxListEvent& event) { int col = event.GetColumn(); + if ( col == -1 ) + { + return; // clicked outside any column. + } + // set or unset image static bool x = false; x = !x; @@ -1409,8 +1436,6 @@ void MyListCtrl::OnListKeyDown(wxListEvent& event) wxFALLTHROUGH; default: - LogEvent(event, "OnListKeyDown"); - event.Skip(); } } diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 45e698960d..c47314ee24 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -950,6 +950,7 @@ bool wxListLineData::Highlight( bool on ) return false; m_highlighted = on; + m_owner->UpdateSelectionCount(on); return true; } @@ -1571,6 +1572,7 @@ wxEND_EVENT_TABLE() void wxListMainWindow::Init() { m_dirty = true; + m_selCount = m_countVirt = 0; m_lineFrom = m_lineTo = (size_t)-1; @@ -1598,7 +1600,8 @@ void wxListMainWindow::Init() m_current = m_lineLastClicked = m_lineSelectSingleOnUp = - m_lineBeforeLastClicked = (size_t)-1; + m_lineBeforeLastClicked = + m_anchor = (size_t)-1; m_hasCheckBoxes = false; } @@ -1866,8 +1869,13 @@ bool wxListMainWindow::IsHighlighted(size_t line) const void wxListMainWindow::HighlightLines( size_t lineFrom, size_t lineTo, - bool highlight ) + bool highlight, + SendEvent sendEvent ) { + // It is safe to swap the bounds here if they are not in order. + if ( lineFrom > lineTo ) + wxSwap(lineFrom, lineTo); + if ( IsVirtual() ) { wxArrayInt linesChanged; @@ -1890,13 +1898,13 @@ void wxListMainWindow::HighlightLines( size_t lineFrom, { for ( size_t line = lineFrom; line <= lineTo; line++ ) { - if ( HighlightLine(line, highlight) ) + if ( HighlightLine(line, highlight, sendEvent) ) RefreshLine(line); } } } -bool wxListMainWindow::HighlightLine( size_t line, bool highlight ) +bool wxListMainWindow::HighlightLine( size_t line, bool highlight, SendEvent sendEvent ) { bool changed; @@ -1912,7 +1920,7 @@ bool wxListMainWindow::HighlightLine( size_t line, bool highlight ) changed = ld->Highlight(highlight); } - if ( changed ) + if ( changed && sendEvent ) { SendNotify( line, highlight ? wxEVT_LIST_ITEM_SELECTED : wxEVT_LIST_ITEM_DESELECTED ); @@ -2197,6 +2205,58 @@ void wxListMainWindow::HighlightAll( bool on ) } } +void wxListMainWindow::HighlightOnly( size_t line, size_t oldLine ) +{ + const unsigned selCount = GetSelectedItemCount(); + + if ( selCount == 1 && IsHighlighted(line) ) + { + return; // Nothing changed. + } + + if ( oldLine != (size_t)-1 ) + { + IsHighlighted(oldLine) ? ReverseHighlight(oldLine) + : RefreshLine(oldLine); // refresh the old focus to remove it + } + + if ( selCount > 1 ) // multiple-selection only + { + // Deselecting many items at once will generate wxEVT_XXX_DESELECTED event + // for each one of them. although this may be inefficient if the number of + // deselected items is too much, we keep doing this (for non-virtual list + // controls) for backward compatibility concerns. For virtual listctrl (in + // multi-selection mode), wxMSW sends only a notification to indicate that + // something has been deselected. Notice that to be fully compatible with + // wxMSW behaviour, _line_ shouldn't be deselected if it was selected. + + const SendEvent sendEvent = IsVirtual() ? SendEvent_None : SendEvent_Normal; + + size_t lineFrom = 0, + lineTo = GetItemCount() - 1; + + if ( line > lineFrom && line < lineTo ) + { + HighlightLines(lineFrom, line - 1, false, sendEvent); + HighlightLines(line + 1, lineTo, false, sendEvent); + } + else // _line_ is equal to lineFrom or lineTo + { + line == lineFrom ? ++lineFrom : --lineTo; + HighlightLines(lineFrom, lineTo, false, sendEvent); + } + + // If we didn't send the event for individual items above, send it for all of them now. + if ( sendEvent == SendEvent_None ) + SendNotify((size_t)-1, wxEVT_LIST_ITEM_DESELECTED); + } + + // _line_ should be the only selected item. + HighlightLine(line); + // refresh the new focus to add it. + RefreshLine(line); +} + void wxListMainWindow::OnChildFocus(wxChildFocusEvent& WXUNUSED(event)) { // Do nothing here. This prevents the default handler in wxScrolledWindow @@ -2241,8 +2301,13 @@ void wxListMainWindow::SendNotify( size_t line, GetParent()->GetEventHandler()->ProcessEvent( le ); } -void wxListMainWindow::ChangeCurrent(size_t current) +bool wxListMainWindow::ChangeCurrentWithoutEvent(size_t current) { + if ( current == m_current ) + { + return false; // Nothing changed! + } + m_current = current; // as the current item changed, we shouldn't start editing it when the @@ -2250,7 +2315,13 @@ void wxListMainWindow::ChangeCurrent(size_t current) if ( m_renameTimer->IsRunning() ) m_renameTimer->Stop(); - SendNotify(current, wxEVT_LIST_ITEM_FOCUSED); + return true; +} + +void wxListMainWindow::ChangeCurrent(size_t current) +{ + if ( ChangeCurrentWithoutEvent(current) ) + SendNotify(current, wxEVT_LIST_ITEM_FOCUSED); } wxTextCtrl *wxListMainWindow::EditLabel(long item, wxClassInfo* textControlClass) @@ -2396,7 +2467,11 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) evtCtx.SetEventObject(GetParent()); GetParent()->GetEventHandler()->ProcessEvent(evtCtx); } - return; + + if ( IsEmpty() ) + return; + + // Continue processing... } if (m_dirty) @@ -2521,8 +2596,7 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) if (m_lineSelectSingleOnUp != (size_t)-1) { // select single line - HighlightAll( false ); - ReverseHighlight(m_lineSelectSingleOnUp); + HighlightOnly(m_lineSelectSingleOnUp); } if (m_lastOnSame) @@ -2542,6 +2616,14 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) m_lastOnSame = false; } + if ( GetSelectedItemCount() == 1 || event.CmdDown() ) + { + // In multiple selection mode, the anchor is set to the first selected + // item or can be changed to m_current if Ctrl key is down, as is the + // case under wxMSW. + m_anchor = m_current; + } + m_lineSelectSingleOnUp = (size_t)-1; } else @@ -2561,9 +2643,8 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) // Multi-selections should not be cleared if a selected item is clicked. if (!IsHighlighted(current)) { - HighlightAll(false); ChangeCurrent(current); - ReverseHighlight(m_current); + HighlightOnly(m_current); } SendNotify( current, wxEVT_LIST_ITEM_RIGHT_CLICK, event.GetPosition() ); @@ -2581,7 +2662,7 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) m_lineLastClicked = current; size_t oldCurrent = m_current; - bool oldWasSelected = IsHighlighted(m_current); + bool oldWasSelected = HasCurrent() && IsHighlighted(m_current); bool cmdModifierDown = event.CmdDown(); if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) ) @@ -2592,11 +2673,8 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) } else if (IsSingleSel() || !IsHighlighted(current)) { - HighlightAll(false); - ChangeCurrent(current); - - ReverseHighlight(m_current); + HighlightOnly(m_current, oldWasSelected ? oldCurrent : (size_t)-1); } else // multi sel & current is highlighted & no mod keys { @@ -2616,16 +2694,15 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) { ChangeCurrent(current); - size_t lineFrom = oldCurrent, - lineTo = current; - - if ( lineTo < lineFrom ) + if ( oldCurrent == (size_t)-1 ) { - lineTo = lineFrom; - lineFrom = m_current; + // Highlight m_current only if there is no previous selection. + HighlightLine(m_current); + } + else if ( oldCurrent != current && m_anchor != (size_t)-1 ) + { + ExtendSelection(oldCurrent, current); } - - HighlightLines(lineFrom, lineTo); } else // !ctrl, !shift { @@ -2634,7 +2711,7 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) } } - if (m_current != oldCurrent) + if (m_current != oldCurrent && oldCurrent != (size_t)-1) RefreshLine( oldCurrent ); // Set the flag telling us whether the next click on this item should @@ -2739,6 +2816,81 @@ bool wxListMainWindow::ScrollList(int WXUNUSED(dx), int dy) // keyboard handling // ---------------------------------------------------------------------------- +// Helper function which handles items selection correctly and efficiently. and +// simply, mimic the wxMSW behaviour. And The benefit of this function is that it +// ensures that wxEVT_LIST_ITEM_{DE}SELECTED events are only generated for items +// freshly (de)selected (i.e. items that have really changed state). Useful for +// multi-selection mode when selecting using mouse or arrows with Shift key down. +void wxListMainWindow::ExtendSelection(size_t oldCurrent, size_t newCurrent) +{ + // Refresh the old/new focus to remove/add it + RefreshLine(oldCurrent); + RefreshLine(newCurrent); + + // Given a selection [anchor, old], to change/extend it to new (i.e. the + // selection becomes [anchor, new]) we discriminate three possible cases: + // + // Case 1) new < old <= anchor || anchor <= old < new + // i.e. oldCurrent between anchor and newCurrent, in which case we: + // - Highlight everything between anchor and newCurrent (inclusive). + // + // Case 2) old < new <= anchor || anchor <= new < old + // i.e. newCurrent between anchor and oldCurrent, in which case we: + // - Unhighlight everything between oldCurrent and newCurrent (exclusive). + // + // Case 3) old < anchor < new || new < anchor < old + // i.e. anchor between oldCurrent and newCurrent, in which case we + // - Highlight everything between anchor and newCurrent (inclusive). + // - Unhighlight everything between anchor (exclusive) and oldCurrent. + + size_t lineFrom, lineTo; + + if ( (newCurrent < oldCurrent && oldCurrent <= m_anchor) || + (newCurrent > oldCurrent && oldCurrent >= m_anchor) ) + { + lineFrom = m_anchor; + lineTo = newCurrent; + + HighlightLines(lineFrom, lineTo); + } + else if ( (oldCurrent < newCurrent && newCurrent <= m_anchor) || + (oldCurrent > newCurrent && newCurrent >= m_anchor) ) + { + lineFrom = oldCurrent; + lineTo = newCurrent; + + // Exclude newCurrent from being deselected + (lineTo < lineFrom) ? ++lineTo : --lineTo; + + HighlightLines(lineFrom, lineTo, false); + + // For virtual listctrl (in multi-selection mode), wxMSW sends only + // a notification to indicate that something has been deselected. + if ( IsVirtual() ) + SendNotify((size_t)-1, wxEVT_LIST_ITEM_DESELECTED); + } + else if ( (oldCurrent < m_anchor && m_anchor < newCurrent) || + (newCurrent < m_anchor && m_anchor < oldCurrent) ) + { + lineFrom = m_anchor; + lineTo = oldCurrent; + + // Exclude anchor from being deselected + (lineTo < lineFrom) ? --lineFrom : ++lineFrom; + + HighlightLines(lineFrom, lineTo, false); + + // See above. + if ( IsVirtual() ) + SendNotify((size_t)-1, wxEVT_LIST_ITEM_DESELECTED); + + lineFrom = m_anchor; + lineTo = newCurrent; + + HighlightLines(lineFrom, lineTo); + } +} + void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event) { wxCHECK_RET( newCurrent < (size_t)GetItemCount(), @@ -2746,43 +2898,34 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event) size_t oldCurrent = m_current; + ChangeCurrent(newCurrent); + // in single selection we just ignore Shift as we can't select several // items anyhow if ( event.ShiftDown() && !IsSingleSel() ) { - ChangeCurrent(newCurrent); - - // refresh the old focus to remove it - RefreshLine( oldCurrent ); - - // select all the items between the old and the new one - if ( oldCurrent > newCurrent ) - { - newCurrent = oldCurrent; - oldCurrent = m_current; - } - - HighlightLines(oldCurrent, newCurrent); + ExtendSelection(oldCurrent, newCurrent); } else // !shift { - // all previously selected items are unselected unless ctrl is held - // in a multiselection control + // all previously selected items are unselected unless ctrl is held in + // a multi-selection control. in single selection mode we must always + // have a selected item. if ( !event.ControlDown() || IsSingleSel() ) - HighlightAll(false); + { + HighlightOnly(m_current, oldCurrent); - ChangeCurrent(newCurrent); - - // refresh the old focus to remove it - RefreshLine( oldCurrent ); - - // in single selection mode we must always have a selected item - if ( !event.ControlDown() || IsSingleSel() ) - HighlightLine( m_current, true ); + // Update anchor + m_anchor = m_current; + } + else + { + // refresh the old/new focus to remove/add it + RefreshLine(oldCurrent); + RefreshLine(m_current); + } } - RefreshLine( m_current ); - MoveToFocus(); } @@ -2799,10 +2942,11 @@ void wxListMainWindow::OnKeyDown( wxKeyEvent &event ) // send a list event wxListEvent le( wxEVT_LIST_KEY_DOWN, parent->GetId() ); + const size_t current = ShouldSendEventForCurrent() ? m_current : (size_t)-1; le.m_item.m_itemId = - le.m_itemIndex = m_current; - if (HasCurrent()) - GetLine(m_current)->GetItem( 0, le.m_item ); + le.m_itemIndex = current; + if ( current != (size_t)-1 ) + GetLine(current)->GetItem( 0, le.m_item ); le.m_code = event.GetKeyCode(); le.SetEventObject( parent ); if (parent->GetEventHandler()->ProcessEvent( le )) @@ -2956,7 +3100,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event ) { ReverseHighlight(m_current); } - else // normal space press + else if ( ShouldSendEventForCurrent() ) // normal space press { SendNotify( m_current, wxEVT_LIST_ITEM_ACTIVATED ); } @@ -2969,7 +3113,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event ) case WXK_RETURN: case WXK_EXECUTE: - if ( event.HasModifiers() ) + if ( event.HasModifiers() || !ShouldSendEventForCurrent() ) { event.Skip(); break; @@ -3078,6 +3222,7 @@ void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) { m_hasFocus = true; + UpdateCurrent(); RefreshSelected(); } } @@ -3621,17 +3766,7 @@ int wxListMainWindow::GetSelectedItemCount() const if ( IsVirtual() ) return m_selStore.GetSelectedCount(); - // TODO: we probably should maintain the number of items selected even for - // non virtual controls as enumerating all lines is really slow... - size_t countSel = 0; - size_t count = GetItemCount(); - for ( size_t line = 0; line < count; line++ ) - { - if ( GetLine(line)->IsHighlighted() ) - countSel++; - } - - return countSel; + return m_selCount; } // ---------------------------------------------------------------------------- @@ -4036,9 +4171,6 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) if ( !noRefresh ) { - // FIXME: why should we call it from here? - UpdateCurrent(); - RefreshAll(); } } @@ -4059,7 +4191,13 @@ void wxListMainWindow::RefreshAll() void wxListMainWindow::UpdateCurrent() { if ( !HasCurrent() && !IsEmpty() ) - ChangeCurrent(0); + { + // Initialise m_current to the first item without sending any + // wxEVT_LIST_ITEM_FOCUSED event (typicaly when the control gains focus) + // and this is to allow changing the focused item using the arrow keys. + // which is the behaviour found in the wxMSW port. + ChangeCurrentWithoutEvent(0); + } } long wxListMainWindow::GetNextItem( long item, @@ -4248,6 +4386,10 @@ void wxListMainWindow::DoDeleteAllItems() m_countVirt = 0; m_selStore.Clear(); } + else + { + m_selCount = 0; + } if ( InReportView() ) ResetVisibleLinesRange(); diff --git a/tests/controls/listbasetest.cpp b/tests/controls/listbasetest.cpp index 2bee21811d..5673676e74 100644 --- a/tests/controls/listbasetest.cpp +++ b/tests/controls/listbasetest.cpp @@ -26,6 +26,7 @@ #include "wx/uiaction.h" #include "wx/imaglist.h" #include "wx/artprov.h" +#include "wx/stopwatch.h" void ListBaseTestCase::ColumnsOrder() { @@ -177,6 +178,123 @@ void ListBaseTestCase::ChangeMode() CPPUNIT_ASSERT_EQUAL( "First", list->GetItemText(0) ); } +#ifdef __WXGTK__ + #define wxGTK_TIMED_YIELD(t) \ + if ( !IsRunningUnderXVFB() ) \ + for ( wxStopWatch sw; sw.Time() < t; ) wxYield() +#else // !__WXGTK__ + #define wxGTK_TIMED_YIELD(t) +#endif // __WXGTK__ + +void ListBaseTestCase::MultiSelect() +{ +#if wxUSE_UIACTIONSIMULATOR + +#ifndef __WXMSW__ + // FIXME: This test fails on Travis CI although works fine on + // development machine, no idea why though! + if ( IsAutomaticTest() ) + return; +#endif // !__WXMSW__ + + wxListCtrl* const list = GetList(); + + EventCounter focused(list, wxEVT_LIST_ITEM_FOCUSED); + EventCounter selected(list, wxEVT_LIST_ITEM_SELECTED); + EventCounter deselected(list, wxEVT_LIST_ITEM_DESELECTED); + + list->InsertColumn(0, "Header"); + + for ( int i = 0; i < 10; ++i ) + list->InsertItem(i, wxString::Format("Item %d", i)); + + wxUIActionSimulator sim; + + wxRect pos; + list->GetItemRect(2, pos); // Choose the third item as anchor + + // We move in slightly so we are not on the edge + wxPoint point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 10); + + sim.MouseMove(point); + wxYield(); + + sim.MouseClick(); // select the anchor + wxYield(); + + wxGTK_TIMED_YIELD(50); + + list->GetItemRect(5, pos); + point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 10); + + sim.MouseMove(point); + wxYield(); + + sim.KeyDown(WXK_SHIFT); + sim.MouseClick(); + sim.KeyUp(WXK_SHIFT); + wxYield(); + + wxGTK_TIMED_YIELD(10); + + // when the first item was selected the focus changes to it, but not + // on subsequent clicks + CPPUNIT_ASSERT_EQUAL(4, list->GetSelectedItemCount()); // item 2 to 5 (inclusive) are selected + CPPUNIT_ASSERT_EQUAL(2, focused.GetCount()); // count the focus which was on the anchor + CPPUNIT_ASSERT_EQUAL(4, selected.GetCount()); + CPPUNIT_ASSERT_EQUAL(0, deselected.GetCount()); + + focused.Clear(); + selected.Clear(); + deselected.Clear(); + + sim.Char(WXK_END, wxMOD_SHIFT); // extend the selection to the last item + wxYield(); + + wxGTK_TIMED_YIELD(10); + + CPPUNIT_ASSERT_EQUAL(8, list->GetSelectedItemCount()); // item 2 to 9 (inclusive) are selected + CPPUNIT_ASSERT_EQUAL(1, focused.GetCount()); // focus is on the last item + CPPUNIT_ASSERT_EQUAL(4, selected.GetCount()); // only newly selected items got the event + CPPUNIT_ASSERT_EQUAL(0, deselected.GetCount()); + + focused.Clear(); + selected.Clear(); + deselected.Clear(); + + sim.Char(WXK_HOME, wxMOD_SHIFT); // select from anchor to the first item + wxYield(); + + wxGTK_TIMED_YIELD(10); + + CPPUNIT_ASSERT_EQUAL(3, list->GetSelectedItemCount()); // item 0 to 2 (inclusive) are selected + CPPUNIT_ASSERT_EQUAL(1, focused.GetCount()); // focus is on item 0 + CPPUNIT_ASSERT_EQUAL(2, selected.GetCount()); // events are only generated for item 0 and 1 + CPPUNIT_ASSERT_EQUAL(7, deselected.GetCount()); // item 2 (exclusive) to 9 are deselected + + focused.Clear(); + selected.Clear(); + deselected.Clear(); + + list->EnsureVisible(0); + wxYield(); + + list->GetItemRect(2, pos); + point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 10); + + sim.MouseMove(point); + wxYield(); + + sim.MouseClick(); + wxYield(); + + CPPUNIT_ASSERT_EQUAL(1, list->GetSelectedItemCount()); // anchor is the only selected item + CPPUNIT_ASSERT_EQUAL(1, focused.GetCount()); // because the focus changed from item 0 to anchor + CPPUNIT_ASSERT_EQUAL(0, selected.GetCount()); // anchor is already in selection state + CPPUNIT_ASSERT_EQUAL(2, deselected.GetCount()); // items 0 and 1 are deselected +#endif // wxUSE_UIACTIONSIMULATOR +} + void ListBaseTestCase::ItemClick() { #if wxUSE_UIACTIONSIMULATOR @@ -236,16 +354,9 @@ void ListBaseTestCase::ItemClick() // when the first item was selected the focus changes to it, but not // on subsequent clicks - - // FIXME: This test fail under wxGTK & wxOSX because we get 3 FOCUSED events and - // 2 SELECTED ones instead of the one of each we expect for some - // reason, this needs to be debugged as it may indicate a bug in the - // generic wxListCtrl implementation. -#ifndef _WX_GENERIC_LISTCTRL_H_ CPPUNIT_ASSERT_EQUAL(1, focused.GetCount()); CPPUNIT_ASSERT_EQUAL(1, selected.GetCount()); CPPUNIT_ASSERT_EQUAL(1, deselected.GetCount()); -#endif CPPUNIT_ASSERT_EQUAL(1, activated.GetCount()); CPPUNIT_ASSERT_EQUAL(1, rclick.GetCount()); #endif // wxUSE_UIACTIONSIMULATOR diff --git a/tests/controls/listbasetest.h b/tests/controls/listbasetest.h index d5840767c9..8b8df808b7 100644 --- a/tests/controls/listbasetest.h +++ b/tests/controls/listbasetest.h @@ -26,6 +26,7 @@ protected: CPPUNIT_TEST( ChangeMode ); \ WXUISIM_TEST( ItemClick ); \ WXUISIM_TEST( KeyDown ); \ + WXUISIM_TEST( MultiSelect ); \ CPPUNIT_TEST( DeleteItems ); \ CPPUNIT_TEST( InsertItem ); \ CPPUNIT_TEST( Find ); \ @@ -40,6 +41,7 @@ protected: void ItemRect(); void ItemText(); void ChangeMode(); + void MultiSelect(); void ItemClick(); void KeyDown(); void DeleteItems(); diff --git a/tests/controls/listviewtest.cpp b/tests/controls/listviewtest.cpp index 94162d3eab..1ddd6c6f33 100644 --- a/tests/controls/listviewtest.cpp +++ b/tests/controls/listviewtest.cpp @@ -20,6 +20,7 @@ #include "wx/listctrl.h" #include "listbasetest.h" +#include "testableframe.h" class ListViewTestCase : public ListBaseTestCase, public CppUnit::TestCase { @@ -61,7 +62,8 @@ void ListViewTestCase::setUp() void ListViewTestCase::tearDown() { - wxDELETE(m_list); + DeleteTestWindow(m_list); + m_list = NULL; } void ListViewTestCase::Selection() @@ -104,6 +106,8 @@ void ListViewTestCase::Selection() void ListViewTestCase::Focus() { + EventCounter focused(m_list, wxEVT_LIST_ITEM_FOCUSED); + m_list->InsertColumn(0, "Column 0"); m_list->InsertItem(0, "Item 0"); @@ -111,10 +115,12 @@ void ListViewTestCase::Focus() m_list->InsertItem(2, "Item 2"); m_list->InsertItem(3, "Item 3"); + CPPUNIT_ASSERT_EQUAL(0, focused.GetCount()); CPPUNIT_ASSERT_EQUAL(-1, m_list->GetFocusedItem()); m_list->Focus(0); + CPPUNIT_ASSERT_EQUAL(1, focused.GetCount()); CPPUNIT_ASSERT_EQUAL(0, m_list->GetFocusedItem()); } From fafc5613f4c56f8b2ff7570ab0e7130f0756cfef Mon Sep 17 00:00:00 2001 From: PB Date: Sat, 10 Oct 2020 19:38:34 +0200 Subject: [PATCH 104/105] Fix slider event counter in widgets sample Commit 952e5f3 introduced logging wxEVT_SLIDER events in addition to scrolling events but the event count was incorrect as the wxEVT_SLIDER handler and scrolling events handler kept their own event count. Fix this by using a static member variable shared by both event handlers. --- samples/widgets/slider.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/samples/widgets/slider.cpp b/samples/widgets/slider.cpp index 4fbda64f11..75e9b2145c 100644 --- a/samples/widgets/slider.cpp +++ b/samples/widgets/slider.cpp @@ -162,6 +162,8 @@ protected: bool IsValidValue(int val) const { return (val >= m_min) && (val <= m_max); } + static int ms_numSliderEvents; + // the slider range int m_min, m_max; @@ -201,6 +203,8 @@ private: DECLARE_WIDGETS_PAGE(SliderWidgetsPage) }; +int SliderWidgetsPage::ms_numSliderEvents = 0; + // ---------------------------------------------------------------------------- // event tables // ---------------------------------------------------------------------------- @@ -837,11 +841,8 @@ void SliderWidgetsPage::OnSlider(wxScrollEvent& event) wxASSERT_MSG(index >= 0 && (size_t)index < WXSIZEOF(eventNames), "Unknown slider event" ); - - static int s_numSliderEvents = 0; - wxLogMessage("Slider event #%d: %s (pos = %d, int value = %d)", - s_numSliderEvents++, + ms_numSliderEvents++, eventNames[index], event.GetPosition(), event.GetInt()); @@ -849,10 +850,8 @@ void SliderWidgetsPage::OnSlider(wxScrollEvent& event) void SliderWidgetsPage::OnSlider(wxCommandEvent& event) { - static int s_numSliderEvents = 0; - wxLogMessage("Slider event #%d: wxEVT_SLIDER (value = %d)", - s_numSliderEvents++, event.GetInt()); + ms_numSliderEvents++, event.GetInt()); } #endif // wxUSE_SLIDER From ae8820b2f63145bfb9d3414142d52e7f6b33c064 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 10 Oct 2020 22:22:48 +0200 Subject: [PATCH 105/105] Fix build error with clang in the widgets sample Don't use overloaded function as event handler. --- samples/widgets/slider.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/widgets/slider.cpp b/samples/widgets/slider.cpp index 75e9b2145c..383be8b14a 100644 --- a/samples/widgets/slider.cpp +++ b/samples/widgets/slider.cpp @@ -119,7 +119,7 @@ protected: void OnCheckOrRadioBox(wxCommandEvent& event); - void OnSlider(wxScrollEvent& event); + void OnSliderScroll(wxScrollEvent& event); void OnSlider(wxCommandEvent& event); void OnUpdateUIValueButton(wxUpdateUIEvent& event); @@ -234,7 +234,7 @@ wxBEGIN_EVENT_TABLE(SliderWidgetsPage, WidgetsPage) EVT_UPDATE_UI(SliderPage_CurValueText, SliderWidgetsPage::OnUpdateUICurValueText) - EVT_COMMAND_SCROLL(SliderPage_Slider, SliderWidgetsPage::OnSlider) + EVT_COMMAND_SCROLL(SliderPage_Slider, SliderWidgetsPage::OnSliderScroll) EVT_SLIDER(SliderPage_Slider, SliderWidgetsPage::OnSlider) EVT_CHECKBOX(wxID_ANY, SliderWidgetsPage::OnCheckOrRadioBox) @@ -807,7 +807,7 @@ void SliderWidgetsPage::OnUpdateUISelectRange(wxUpdateUIEvent& event) #endif // defined(__WXMSW__) } -void SliderWidgetsPage::OnSlider(wxScrollEvent& event) +void SliderWidgetsPage::OnSliderScroll(wxScrollEvent& event) { wxASSERT_MSG( event.GetInt() == m_slider->GetValue(), "slider value should be the same" );