[Git][wxwidgets/wxwidgets][master] 9 commits: wxQt: Rewrite wxDC::ComputeScaleAndOrigin() member function

1 view
Skip to first unread message

Vadim Zeitlin (@_VZ_)

unread,
May 8, 2026, 11:15:41 AM (8 days ago) May 8
to wx-commi...@googlegroups.com

Vadim Zeitlin pushed to branch master at wxWidgets / wxWidgets

Commits:

  • c6776276
    by ali kettab at 2026-04-20T23:06:26+01:00
    wxQt: Rewrite wxDC::ComputeScaleAndOrigin() member function
    
    No real changes, just a minor simplification and rearrangement for the upcoming commit.
    
  • bb1cc62d
    by Vadim Zeitlin at 2026-05-02T18:17:11+02:00
    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.
    
  • 2d3a6d8f
    by Vadim Zeitlin at 2026-05-03T15:23:51+02:00
    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.
    
  • 250e45e1
    by ali kettab at 2026-05-06T18:22:44+01:00
    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.
    
  • e57681d7
    by ali kettab at 2026-05-06T18:22:44+01:00
    Update OneDevRegionRTL test after recent changes
    
  • 7ffe27e8
    by Vadim Zeitlin at 2026-05-08T16:27:16+02:00
    Disable bogus -Warray-bounds for gcc 16.1 too
    
    Similar to 7eb942431e (Disable bogus -Wmaybe-initialized for gcc 16.1
    too, 2026-05-08).
    
  • 4f8fb4d0
    by Vadim Zeitlin at 2026-05-08T16:28:21+02:00
    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.
    
  • 4371d8f3
    by AliKet at 2026-05-08T16:29:52+02:00
    Fix text rendering in RTL layout when using Direct2D backend
    
    Closes #26430.
    
  • 7fd8ed3f
    by Vadim Zeitlin at 2026-05-08T16:35:50+02:00
    Merge branch 'msw-listctrl-col-width-from-resize'
    
    Fix setting wxListCtrl column widths from wxEVT_SIZE in wxMSW.
    
    See #26422.
    

8 changed files:

Changes:

  • include/wx/msw/listctrl.h
    ... ... @@ -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();
    

  • include/wx/qt/dc.h
    ... ... @@ -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
         {
    

  • interface/wx/listctrl.h
    ... ... @@ -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
     
    

  • src/msw/graphicsd2d.cpp
    ... ... @@ -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()
    

  • src/msw/listctrl.cpp
    ... ... @@ -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);
    

  • src/qt/dc.cpp
    ... ... @@ -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
     }

  • tests/graphics/clippingbox.cpp
    ... ... @@ -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
    

  • tests/misc/guifuncs.cpp
    ... ... @@ -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
     
    

Reply all
Reply to author
Forward
0 new messages