wxQt: Rewrite wxDC::ComputeScaleAndOrigin() member function No real changes, just a minor simplification and rearrangement for the upcoming commit.
Fix setting wxListCtrl column widths from wxEVT_SIZE in wxMSW Calling SetColumnWidth() from wxEVT_SIZE handler could break the native control refresh logic and result in it not being refreshed at all any more. Work around this by delaying actually setting the column width until the resizing is done. Closes #26394.
Document that SetColumnWidth() may not take effect immediately This may be surprising, but hopefully application code should rarely need to call GetColumnWidth() immediately after setting the width.
wxDC::LogicalToDevice{Rel}() now return unmirrored coordinates in RTL under wxQt
Ditto for wxDC::DeviceToLogical{Rel}() functions.
In RTL layout, these functions always return unmirrored coordinates under wxGTK3
This is now the case under wxQt too for consistency and also to fix incorrect
drawings. See wxGrid::Render() for example.
Update OneDevRegionRTL test after recent changes
Disable bogus -Warray-bounds for gcc 16.1 too Similar to 7eb942431e (Disable bogus -Wmaybe-initialized for gcc 16.1 too, 2026-05-08).
Merge branch 'qt-rtl' of github.com:AliKet/wxWidgets Make wxDC::LogicalToDevice() and sister functions return unmirrored coordinates when using RTL in wxQt. See #26401.
Fix text rendering in RTL layout when using Direct2D backend Closes #26430.
Merge branch 'msw-listctrl-col-width-from-resize' Fix setting wxListCtrl column widths from wxEVT_SIZE in wxMSW. See #26422.
| ... | ... | @@ -469,6 +469,12 @@ private: |
| 469 | 469 | // Object using for header custom drawing if necessary, may be null.
|
| 470 | 470 | wxMSWHeaderCtrlCustomDraw* m_headerCustomDraw;
|
| 471 | 471 | |
| 472 | + // Non-zero while we're handling WM_SIZE. This is a counter and not a bool
|
|
| 473 | + // to account for the possibility of nested WM_SIZE messages, as it looks
|
|
| 474 | + // like it might happen if a wxEVT_SIZE handler does something that causes
|
|
| 475 | + // another WM_SIZE to be generated.
|
|
| 476 | + int m_inResize = 0;
|
|
| 477 | + |
|
| 472 | 478 | |
| 473 | 479 | wxDECLARE_DYNAMIC_CLASS(wxListCtrl);
|
| 474 | 480 | wxDECLARE_EVENT_TABLE();
|
| ... | ... | @@ -10,6 +10,7 @@ |
| 10 | 10 | |
| 11 | 11 | class QPainter;
|
| 12 | 12 | class QImage;
|
| 13 | +class QTransform;
|
|
| 13 | 14 | |
| 14 | 15 | class WXDLLIMPEXP_FWD_CORE wxRegion;
|
| 15 | 16 | |
| ... | ... | @@ -140,6 +141,10 @@ protected: |
| 140 | 141 | |
| 141 | 142 | bool m_isClipBoxValid = false;
|
| 142 | 143 | |
| 144 | + // Used by LogicalToDevice()/DeviceToLogical()
|
|
| 145 | + std::unique_ptr<QTransform> m_matrixCurrent;
|
|
| 146 | + std::unique_ptr<QTransform> m_matrixCurrentInv;
|
|
| 147 | + |
|
| 143 | 148 | private:
|
| 144 | 149 | enum wxQtRasterColourOp
|
| 145 | 150 | {
|
| ... | ... | @@ -1104,6 +1104,12 @@ public: |
| 1104 | 1104 | |
| 1105 | 1105 | In small or normal icon view, @a col must be -1, and the column width is set
|
| 1106 | 1106 | for all columns.
|
| 1107 | + |
|
| 1108 | + @note In wxMSW, the width of the column may not change immediately when
|
|
| 1109 | + calling this function from wxEVT_SIZE handler due to the native
|
|
| 1110 | + control limitations and calling GetColumnWidth() immediately after
|
|
| 1111 | + SetColumnWidth() may still return the old width. The width is
|
|
| 1112 | + still guaranteed to be updated after the event handler returns.
|
|
| 1107 | 1113 | */
|
| 1108 | 1114 | bool SetColumnWidth(int col, int width);
|
| 1109 | 1115 |
| ... | ... | @@ -4067,6 +4067,8 @@ private: |
| 4067 | 4067 | bool m_isClipBoxValid;
|
| 4068 | 4068 | double m_clipX1, m_clipY1, m_clipX2, m_clipY2;
|
| 4069 | 4069 | |
| 4070 | + wxLayoutDirection m_layoutDir = wxLayout_Default;
|
|
| 4071 | + |
|
| 4070 | 4072 | private:
|
| 4071 | 4073 | wxDECLARE_NO_COPY_CLASS(wxD2DContext);
|
| 4072 | 4074 | };
|
| ... | ... | @@ -4125,6 +4127,9 @@ wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, |
| 4125 | 4127 | RECT r = wxGetWindowRect(hwnd);
|
| 4126 | 4128 | m_width = r.right - r.left;
|
| 4127 | 4129 | m_height = r.bottom - r.top;
|
| 4130 | + |
|
| 4131 | + m_layoutDir = window->GetLayoutDirection();
|
|
| 4132 | + |
|
| 4128 | 4133 | Init();
|
| 4129 | 4134 | }
|
| 4130 | 4135 | |
| ... | ... | @@ -4154,6 +4159,8 @@ wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, |
| 4154 | 4159 | wxPoint org = dc.GetDeviceOrigin();
|
| 4155 | 4160 | m_inheritedTransform = D2D1::Matrix3x2F::Translation(org.x / sx, org.y / sy);
|
| 4156 | 4161 | |
| 4162 | + m_layoutDir = dc.GetLayoutDirection();
|
|
| 4163 | + |
|
| 4157 | 4164 | Init();
|
| 4158 | 4165 | }
|
| 4159 | 4166 | |
| ... | ... | @@ -4170,6 +4177,10 @@ wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dF |
| 4170 | 4177 | }
|
| 4171 | 4178 | m_width = r.right - r.left;
|
| 4172 | 4179 | m_height = r.bottom - r.top;
|
| 4180 | + |
|
| 4181 | + m_layoutDir = (::GetLayout(hdc) & LAYOUT_RTL) != 0
|
|
| 4182 | + ? wxLayout_RightToLeft : wxLayout_LeftToRight;
|
|
| 4183 | + |
|
| 4173 | 4184 | Init();
|
| 4174 | 4185 | }
|
| 4175 | 4186 | |
| ... | ... | @@ -4822,11 +4833,36 @@ void wxD2DContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y) |
| 4822 | 4833 | |
| 4823 | 4834 | wxCOMPtr<IDWriteTextLayout> textLayout = fontData->CreateTextLayout(str);
|
| 4824 | 4835 | |
| 4836 | + wxGraphicsMatrix oldMatrix;
|
|
| 4837 | + |
|
| 4838 | + if ( m_layoutDir == wxLayout_RightToLeft )
|
|
| 4839 | + {
|
|
| 4840 | + wxDouble width;
|
|
| 4841 | + GetTextExtent(str, &width, nullptr, nullptr, nullptr);
|
|
| 4842 | + |
|
| 4843 | + oldMatrix = GetTransform(); // save old matrix
|
|
| 4844 | + wxGraphicsMatrix matrixRTL = CreateMatrix();
|
|
| 4845 | + // Alternatively, we can translate to (x+width, y) and pass (0, 0) to
|
|
| 4846 | + // GetRenderTarget()->DrawTextLayout() below.
|
|
| 4847 | + matrixRTL.Translate(2*x+width, 0);
|
|
| 4848 | + matrixRTL.Scale(-1, 1);
|
|
| 4849 | + ConcatTransform(matrixRTL);
|
|
| 4850 | + |
|
| 4851 | + textLayout->SetReadingDirection(DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
|
|
| 4852 | + textLayout->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING);
|
|
| 4853 | + }
|
|
| 4854 | + |
|
| 4825 | 4855 | // Render the text
|
| 4826 | 4856 | GetRenderTarget()->DrawTextLayout(
|
| 4827 | 4857 | D2D1::Point2F(x, y),
|
| 4828 | 4858 | textLayout,
|
| 4829 | 4859 | fontData->GetBrushData().GetBrush());
|
| 4860 | + |
|
| 4861 | + if ( m_layoutDir == wxLayout_RightToLeft )
|
|
| 4862 | + {
|
|
| 4863 | + // Restore old matrix
|
|
| 4864 | + SetTransform(oldMatrix);
|
|
| 4865 | + }
|
|
| 4830 | 4866 | }
|
| 4831 | 4867 | |
| 4832 | 4868 | bool wxD2DContext::EnsureInitialized()
|
| ... | ... | @@ -845,6 +845,24 @@ bool wxListCtrl::SetColumnWidth(int col, int width) |
| 845 | 845 | else if ( width == wxLIST_AUTOSIZE_USEHEADER)
|
| 846 | 846 | width = LVSCW_AUTOSIZE_USEHEADER;
|
| 847 | 847 | |
| 848 | + if ( m_inResize )
|
|
| 849 | + {
|
|
| 850 | + // Changing column width while handling WM_SIZE seems to be break
|
|
| 851 | + // something inside the native control, resulting in it not redrawing
|
|
| 852 | + // at all any longer in some circumstances, see #26394, so defer the
|
|
| 853 | + // call until resizing is done.
|
|
| 854 | + CallAfter([this, col, width]()
|
|
| 855 | + {
|
|
| 856 | + // This is a recursive call but it shouldn't recurse for ever (or,
|
|
| 857 | + // normally, more than once) as m_inResize should be reset "soon".
|
|
| 858 | + SetColumnWidth(col, width);
|
|
| 859 | + });
|
|
| 860 | + |
|
| 861 | + // Optimistically assume setting the column width later will succeed:
|
|
| 862 | + // better this than returning a bogus failure.
|
|
| 863 | + return true;
|
|
| 864 | + }
|
|
| 865 | + |
|
| 848 | 866 | if ( !ListView_SetColumnWidth(GetHwnd(), col, width) )
|
| 849 | 867 | return false;
|
| 850 | 868 | |
| ... | ... | @@ -3782,7 +3800,13 @@ wxListCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) |
| 3782 | 3800 | // so just ignore them
|
| 3783 | 3801 | if ( (HWND)wParam == ListView_GetHeader(GetHwnd()) )
|
| 3784 | 3802 | return 0;
|
| 3785 | - //else: break
|
|
| 3803 | + break;
|
|
| 3804 | + |
|
| 3805 | + case WM_SIZE:
|
|
| 3806 | + m_inResize++;
|
|
| 3807 | + auto const rc = wxListCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
|
|
| 3808 | + m_inResize--;
|
|
| 3809 | + return rc;
|
|
| 3786 | 3810 | }
|
| 3787 | 3811 | |
| 3788 | 3812 | return wxListCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
|
| ... | ... | @@ -99,6 +99,9 @@ wxQtDCImpl::wxQtDCImpl( wxDC *owner ) |
| 99 | 99 | m_qtPenColor = new QColor;
|
| 100 | 100 | m_qtBrushColor = new QColor;
|
| 101 | 101 | m_ok = true;
|
| 102 | + |
|
| 103 | + m_matrixCurrent.reset(new QTransform);
|
|
| 104 | + m_matrixCurrentInv.reset(new QTransform);
|
|
| 102 | 105 | }
|
| 103 | 106 | |
| 104 | 107 | wxQtDCImpl::~wxQtDCImpl()
|
| ... | ... | @@ -295,15 +298,14 @@ void wxQtDCImpl::SetPalette(const wxPalette& WXUNUSED(palette)) |
| 295 | 298 | wxPoint wxQtDCImpl::DeviceToLogical(wxCoord x, wxCoord y) const
|
| 296 | 299 | {
|
| 297 | 300 | QPointF devicePoint(x, y);
|
| 298 | - const auto invTrans = m_qtPainter->combinedTransform().inverted();
|
|
| 299 | - QPointF logicalPoint = invTrans.map(devicePoint);
|
|
| 301 | + QPointF logicalPoint = m_matrixCurrentInv->map(devicePoint);
|
|
| 300 | 302 | return wxPoint(wxRound(logicalPoint.x()), wxRound(logicalPoint.y()));
|
| 301 | 303 | }
|
| 302 | 304 | |
| 303 | 305 | wxPoint wxQtDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const
|
| 304 | 306 | {
|
| 305 | 307 | QPointF logicalPoint(x, y);
|
| 306 | - QPointF devicePoint = m_qtPainter->combinedTransform().map(logicalPoint);
|
|
| 308 | + QPointF devicePoint = m_matrixCurrent->map(logicalPoint);
|
|
| 307 | 309 | return wxPoint(wxRound(devicePoint.x()), wxRound(devicePoint.y()));
|
| 308 | 310 | }
|
| 309 | 311 | |
| ... | ... | @@ -1087,10 +1089,22 @@ void wxQtDCImpl::DoDrawPolyPolygon(int n, |
| 1087 | 1089 | |
| 1088 | 1090 | void wxQtDCImpl::ComputeScaleAndOrigin()
|
| 1089 | 1091 | {
|
| 1090 | - QTransform t;
|
|
| 1092 | + wxDCImpl::ComputeScaleAndOrigin();
|
|
| 1093 | + |
|
| 1094 | + QTransform matrixCurrent;
|
|
| 1095 | + |
|
| 1096 | + matrixCurrent.translate( m_deviceOriginX + m_deviceLocalOriginX - m_logicalOriginX * m_signX * m_scaleX,
|
|
| 1097 | + m_deviceOriginY + m_deviceLocalOriginY - m_logicalOriginY * m_signY * m_scaleY );
|
|
| 1098 | + |
|
| 1099 | + matrixCurrent.scale( m_scaleX * m_signX, m_scaleY * m_signY );
|
|
| 1100 | + |
|
| 1101 | + *m_matrixCurrent = matrixCurrent;
|
|
| 1102 | + *m_matrixCurrentInv = matrixCurrent.inverted();
|
|
| 1091 | 1103 | |
| 1092 | 1104 | if ( GetLayoutDirection() == wxLayout_RightToLeft )
|
| 1093 | 1105 | {
|
| 1106 | + QTransform matrixRTL;
|
|
| 1107 | + |
|
| 1094 | 1108 | int w;
|
| 1095 | 1109 | |
| 1096 | 1110 | if ( m_window )
|
| ... | ... | @@ -1098,24 +1112,14 @@ void wxQtDCImpl::ComputeScaleAndOrigin() |
| 1098 | 1112 | else
|
| 1099 | 1113 | GetSize(&w, nullptr);
|
| 1100 | 1114 | |
| 1101 | - t.translate(w, 0);
|
|
| 1102 | - t.scale(-1, 1);
|
|
| 1103 | - }
|
|
| 1104 | - |
|
| 1105 | - // First apply device origin
|
|
| 1106 | - t.translate( m_deviceOriginX + m_deviceLocalOriginX,
|
|
| 1107 | - m_deviceOriginY + m_deviceLocalOriginY );
|
|
| 1115 | + matrixRTL.translate(w, 0);
|
|
| 1116 | + matrixRTL.scale(-1, 1);
|
|
| 1108 | 1117 | |
| 1109 | - // Second, scale
|
|
| 1110 | - m_scaleX = m_logicalScaleX * m_userScaleX;
|
|
| 1111 | - m_scaleY = m_logicalScaleY * m_userScaleY;
|
|
| 1112 | - t.scale( m_scaleX * m_signX, m_scaleY * m_signY );
|
|
| 1113 | - |
|
| 1114 | - // Finally, logical origin
|
|
| 1115 | - t.translate( -m_logicalOriginX, -m_logicalOriginY );
|
|
| 1118 | + matrixCurrent *= matrixRTL;
|
|
| 1119 | + }
|
|
| 1116 | 1120 | |
| 1117 | 1121 | // Apply transform to QPainter, overwriting the previous one
|
| 1118 | - m_qtPainter->setWorldTransform(t, false);
|
|
| 1122 | + m_qtPainter->setWorldTransform(matrixCurrent, false);
|
|
| 1119 | 1123 | |
| 1120 | 1124 | m_isClipBoxValid = false;
|
| 1121 | 1125 | } |
| ... | ... | @@ -1059,7 +1059,7 @@ static void OneDevRegionRTL(wxDC& dc, const wxBitmap& bmp, bool useTransformMatr |
| 1059 | 1059 | const int x2 = s_dcSize.x - (x + w);
|
| 1060 | 1060 | // In a mirrored DC, the device origin (0, 0) is always at the top left
|
| 1061 | 1061 | // of the DC under wxMSW, but under wxGTK3 is at the top right.
|
| 1062 | -#if defined(__WXGTK3__)
|
|
| 1062 | +#if defined(__WXGTK3__) || defined(__WXQT__)
|
|
| 1063 | 1063 | wxPoint pos = dc.DeviceToLogical(x, y);
|
| 1064 | 1064 | wxSize dim = dc.DeviceToLogicalRel(w, h);
|
| 1065 | 1065 | #else
|
| ... | ... | @@ -34,7 +34,7 @@ |
| 34 | 34 | // gcc 16.0 gives many bogus warnings about array subscripts being out of
|
| 35 | 35 | // bounds in basic_string.h, so disable them for this particular version as it
|
| 36 | 36 | // looks like a compiler bug.
|
| 37 | -#if wxCHECK_GCC_VERSION(16, 0) && !wxCHECK_GCC_VERSION(16, 1)
|
|
| 37 | +#if wxCHECK_GCC_VERSION(16, 0) && !wxCHECK_GCC_VERSION(16, 2)
|
|
| 38 | 38 | wxGCC_WARNING_SUPPRESS(array-bounds)
|
| 39 | 39 | #endif
|
| 40 | 40 |
—
View it on GitLab.
You're receiving this email because of your account on gitlab.com. Manage all notifications · Help