diff --git a/include/wx/qt/mdi.h b/include/wx/qt/mdi.h index 51c29f66a7..bfef6e7ada 100644 --- a/include/wx/qt/mdi.h +++ b/include/wx/qt/mdi.h @@ -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; diff --git a/src/qt/dc.cpp b/src/qt/dc.cpp index ead34f0dde..da4cb30958 100644 --- a/src/qt/dc.cpp +++ b/src/qt/dc.cpp @@ -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, diff --git a/src/qt/frame.cpp b/src/qt/frame.cpp index 22b856e2c9..99ce8582b7 100644 --- a/src/qt/frame.cpp +++ b/src/qt/frame.cpp @@ -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 ) ) diff --git a/src/qt/mdi.cpp b/src/qt/mdi.cpp index 636ccc0a0b..3d4c96c44e 100644 --- a/src/qt/mdi.cpp +++ b/src/qt/mdi.cpp @@ -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 ) diff --git a/src/qt/textctrl.cpp b/src/qt/textctrl.cpp index 46b0387988..d2c3678c47 100644 --- a/src/qt/textctrl.cpp +++ b/src/qt/textctrl.cpp @@ -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::max(); diff --git a/tests/events/propagation.cpp b/tests/events/propagation.cpp index 378f8df4b7..e4c421bac0 100644 --- a/tests/events/propagation.cpp +++ b/tests/events/propagation.cpp @@ -33,7 +33,9 @@ #include -#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.