Merge branch 'qt-fixes' of github.com:AliKet/wxWidgets

Miscellaneous wxQt fixes.

See #25968.
This commit is contained in:
Vadim Zeitlin
2025-11-16 18:36:00 +01:00
6 changed files with 82 additions and 72 deletions
+5 -4
View File
@@ -36,13 +36,13 @@ public:
QMdiArea* GetQtMdiArea() const;
enum class Layout
enum class Kind
{
MDI,
Tabbed
};
void QtSetPreferredDILayout(Layout layout);
void QtSetPreferredDILayout(Kind layout);
// override/implement base class [pure] virtual methods
// ----------------------------------------------------
@@ -50,7 +50,7 @@ public:
// The default is to return what wxMDIParentFrame::IsTDI() is supposed to
// return under the target platform. i.e. wxMSW and wxOSX return false,
// while wxGTK returns true. Use QtSetPreferredDILayout() to change that.
static bool IsTDI() { return ms_layout == Layout::Tabbed; }
static bool IsTDI() { return ms_layout == Kind::Tabbed; }
virtual void Cascade() override;
virtual void Tile(wxOrientation orient = wxHORIZONTAL) override;
@@ -86,7 +86,7 @@ private:
// TDI=true, MDI=false
// Default to false under Windows, true otherwise.
static Layout ms_layout;
static Kind ms_layout;
wxDECLARE_DYNAMIC_CLASS(wxMDIParentFrame);
};
@@ -154,6 +154,7 @@ class WXDLLIMPEXP_CORE wxMDIClientWindow : public wxMDIClientWindowBase
{
public:
wxMDIClientWindow() = default;
~wxMDIClientWindow();
virtual bool CreateClient(wxMDIParentFrame *parent, long style = wxVSCROLL | wxHSCROLL) override;
+37 -36
View File
@@ -865,8 +865,17 @@ void wxQtDCImpl::DoDrawBitmap(const wxBitmap &bmp, wxCoord x, wxCoord y,
}
void wxQtDCImpl::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
{
DoDrawRotatedText(text, x, y, 0.0);
}
void wxQtDCImpl::DoDrawRotatedText(const wxString& text,
wxCoord x, wxCoord y, double angle)
{
m_qtPainter->save();
// Move and rotate (reverse angle direction in Qt and wx)
m_qtPainter->translate(x, y);
m_qtPainter->rotate(-angle);
m_qtPainter->setPen(QPen(m_textForegroundColour.GetQColor()));
@@ -884,57 +893,49 @@ void wxQtDCImpl::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
{
// text is not mirrored
m_qtPainter->scale(-1, 1);
x = -x;
}
QRect boundingRect; // Bounding rectangle for non rotated text.
QRect* boundingRectPtr = AreAutomaticBoundingBoxUpdatesEnabled()
? &boundingRect : nullptr;
QFontMetrics metrics = m_qtPainter->fontMetrics();
int lineSpacing = 0;
wxStringTokenizer tokenizer(text, "\n");
while ( tokenizer.HasMoreTokens() )
{
const wxString line = tokenizer.GetNextToken();
m_qtPainter->drawText(x, y, 1, 1, Qt::TextDontClip, wxQtConvertString(line));
y += metrics.lineSpacing();
m_qtPainter->drawText(0, lineSpacing, 1, 1, Qt::TextDontClip,
wxQtConvertString(line), boundingRectPtr);
lineSpacing += metrics.lineSpacing();
if ( AreAutomaticBoundingBoxUpdatesEnabled() && wxIsNullDouble(angle) )
{
CalcBoundingBox(wxQtConvertRect(boundingRect));
}
}
m_qtPainter->restore();
}
void wxQtDCImpl::DoDrawRotatedText(const wxString& text,
wxCoord x, wxCoord y, double angle)
{
m_qtPainter->save();
if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
m_qtPainter->setBackgroundMode(Qt::OpaqueMode);
if ( GetLayoutDirection() == wxLayout_RightToLeft )
// Calculate bounding rectangle for rotated text.
if ( AreAutomaticBoundingBoxUpdatesEnabled() && !wxIsNullDouble(angle) )
{
m_qtPainter->scale(-1, 1);
const double rad = wxDegToRad(angle);
x = -x;
angle = -angle;
const QFontMetrics metrics = m_qtPainter->fontMetrics();
const QRect rect = metrics.boundingRect(wxQtConvertString(text));
const int w = rect.width();
const int h = rect.height();
// "upper left" and "upper right"
CalcBoundingBox(x, y, x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
// "bottom left" and "bottom right"
x += (wxCoord)(h*sin(rad));
y += (wxCoord)(h*cos(rad));
CalcBoundingBox(x, y, x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
}
//Move and rotate (reverse angle direction in Qt and wx)
m_qtPainter->translate(x, y);
m_qtPainter->rotate(-angle);
m_qtPainter->setPen(QPen(m_textForegroundColour.GetQColor()));
// Disable logical function
m_qtPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
{
m_qtPainter->setBackgroundMode(Qt::OpaqueMode);
m_qtPainter->setBackground(QBrush(m_textBackgroundColour.GetQColor()));
}
m_qtPainter->drawText(0, 0, 1, 1, Qt::TextDontClip, wxQtConvertString(text));
m_qtPainter->restore();
}
bool wxQtDCImpl::DoBlit(wxCoord xdest, wxCoord ydest,
+5 -1
View File
@@ -62,9 +62,13 @@ bool wxFrame::Create( wxWindow *parent, wxWindowID id, const wxString& title,
{
m_qtWindow = new wxQtMainWindow( parent, this );
// QMainWindow takes ownership of the central widget pointer.
// Not using QScrollArea or wxPanel is intentional here as it makes the
// implementation simpler and more manageable.
//
// Quoting the Qt docs [QMainWindow::setCentralWidget()]:
// QMainWindow takes ownership of the widget pointer and deletes it at
// the appropriate time.
//
GetQMainWindow()->setCentralWidget( new wxQtCentralWidget( this, this ) );
if ( !wxFrameBase::Create( parent, id, title, pos, size, style, name ) )
+23 -10
View File
@@ -27,11 +27,11 @@ static QMdiSubWindow* gs_qtActiveSubWindow = nullptr;
}
/*static*/
wxMDIParentFrame::Layout wxMDIParentFrame::ms_layout =
wxMDIParentFrame::Kind wxMDIParentFrame::ms_layout =
#if defined(__WINDOWS__)
Layout::MDI;
Kind::MDI;
#else // !__WINDOWS__
Layout::Tabbed;
Kind::Tabbed;
#endif // __WINDOWS__
// Central widget helper (provides an area in which MDI windows are displayed):
@@ -89,7 +89,7 @@ bool wxMDIParentFrame::Create(wxWindow *parent,
return true;
}
void wxMDIParentFrame::QtSetPreferredDILayout(Layout layout)
void wxMDIParentFrame::QtSetPreferredDILayout(Kind layout)
{
ms_layout = layout;
@@ -97,11 +97,11 @@ void wxMDIParentFrame::QtSetPreferredDILayout(Layout layout)
switch ( layout )
{
case Layout::MDI:
case Kind::MDI:
viewMode = QMdiArea::SubWindowView;
break;
case Layout::Tabbed:
case Kind::Tabbed:
viewMode = QMdiArea::TabbedView;
break;
@@ -242,10 +242,7 @@ void wxMDIParentFrame::AddWindowMenu()
{
m_windowMenu = new wxMenu;
// Qt offers only "Tile" without specifying any direction, so just
// reuse one of the predifined ids.
if ( ms_layout == Layout::MDI )
if ( ms_layout == Kind::MDI )
{
// Qt offers only "Tile" without specifying any direction, so just
// reuse one of the predifined ids.
@@ -428,6 +425,13 @@ void wxMDIChildFrame::SetMenuBar(wxMenuBar* menuBar)
m_menuBar = menuBar;
if ( m_mdiParent->GetActiveChild() == this )
{
// Attach the menu bar to m_mdiParent immediately if this child
// window is active.
InternalSetMenuBar();
}
// Don't call wxFrameBase::SetMenuBar() here because m_menuBar will be
// attached to m_mdiParent later when this child frame becomes active.
}
@@ -496,6 +500,15 @@ bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long WXUNUSED(sty
return true;
}
wxMDIClientWindow::~wxMDIClientWindow()
{
DestroyChildren();
// Prevent the base class dtor from destroying the underlying qt window, as
// it is owned by QMainWindow.
m_qtWindow = nullptr;
}
// Helper implementation:
wxQtMdiArea::wxQtMdiArea(wxWindow *parent, wxMDIClientWindow *handler )
+6
View File
@@ -126,6 +126,7 @@ class wxQtTextEdit : public wxQtEventSignalHandler< QTextEdit, wxTextCtrl >
{
public:
wxQtTextEdit( wxWindow *parent, wxTextCtrl *handler );
~wxQtTextEdit();
virtual wxString GetValueForProcessEnter() override
{
@@ -778,6 +779,11 @@ wxQtTextEdit::wxQtTextEdit( wxWindow *parent, wxTextCtrl *handler )
});
}
wxQtTextEdit::~wxQtTextEdit()
{
delete m_textLimiter;
}
void wxQtTextEdit::SetMaxLength(unsigned long len)
{
const unsigned long maxlen = std::numeric_limits<int>::max();
+6 -21
View File
@@ -33,7 +33,9 @@
#include <memory>
#include "waitfor.h"
#if defined(__WXGTK__) || defined(__WXQT__)
#include "waitfor.h"
#endif
// FIXME: Currently under OS X testing paint event doesn't work because neither
// calling Refresh()+Update() nor even sending wxPaintEvent directly to
@@ -668,6 +670,7 @@ void EventPropagationTestCase::DocViewCommon(wxFrame* (*newParent)(wxDocManager
wxMenu* const menuChild = CreateTestMenu(child.get());
#ifdef __WXGTK__
// There are a lot of hacks related to child frame menu bar handling in
// wxGTK and, in particular, the code in src/gtk/mdi.cpp relies on getting
// idle events to really put everything in place. Moreover, as wxGTK uses
@@ -679,8 +682,8 @@ void EventPropagationTestCase::DocViewCommon(wxFrame* (*newParent)(wxDocManager
// make things work "as usual".
child->Show();
parent->Show();
child->SetFocus(); // Without this, the test would fail on wxGTK2
YieldForAWhile();
wxYield();
#endif // __WXGTK__
TestEvtSink sinkDoc('d');
doc->Connect(wxEVT_MENU,
@@ -696,25 +699,7 @@ void EventPropagationTestCase::DocViewCommon(wxFrame* (*newParent)(wxDocManager
// Check that wxDocument, wxView, wxDocManager, child frame and the parent
// get the event in order.
#if wxUSE_UIACTIONSIMULATOR
// We use wxUIActionSimulator instead of ASSERT_MENU_EVENT_RESULT because
// using the latter fails with wxQt on Linux.
wxUnusedVar(menuChild);
g_str.clear();
wxUIActionSimulator sim;
sim.Char('m', wxMOD_ALT);
// N.B.: Don't call wxYield() here, as this will cause the menu to appear
// immediately (and enter its internal message loop) and the next line will
// never be executed under wxMSW. In other words, the execution would block
// indefinitely.
sim.Char('a');
wxYield();
CHECK( g_str == "advmcpA" );
#else // !wxUSE_UIACTIONSIMULATOR
ASSERT_MENU_EVENT_RESULT( menuChild, "advmcpA" );
#endif // wxUSE_UIACTIONSIMULATOR
#if wxUSE_TOOLBAR
// Also check that toolbar events get forwarded to the active child.