diff --git a/include/wx/aui/framemanager.h b/include/wx/aui/framemanager.h index 07240e924e..fdb412eaba 100644 --- a/include/wx/aui/framemanager.h +++ b/include/wx/aui/framemanager.h @@ -497,8 +497,6 @@ public: protected: - void UpdateHintWindowConfig(); - void DoFrameLayout(); void LayoutAddPane(wxSizer* container, @@ -611,7 +609,6 @@ protected: double m_dockConstraintX; // 0.0 .. 1.0; max pct of window width a dock can consume double m_dockConstraintY; // 0.0 .. 1.0; max pct of window height a dock can consume - wxFrame* m_hintWnd; // transparent hint window, if supported by platform wxTimer m_hintFadeTimer; // transparent fade timer wxByte m_hintFadeAmt; // transparent fade amount wxByte m_hintFadeMax; // maximum value of hint fade diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index 6c93ae4bfc..901a47835d 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -33,7 +33,7 @@ #include "wx/settings.h" #include "wx/app.h" #include "wx/dcclient.h" - #include "wx/dcscreen.h" + #include "wx/dcmemory.h" #include "wx/toolbar.h" #include "wx/image.h" #include "wx/statusbr.h" @@ -64,6 +64,8 @@ wxDEFINE_EVENT( wxEVT_AUI_FIND_MANAGER, wxAuiManagerEvent ); #include "wx/msw/dc.h" #endif +#include "wx/dcgraph.h" + #include wxIMPLEMENT_DYNAMIC_CLASS(wxAuiManagerEvent, wxEvent); @@ -73,202 +75,18 @@ wxIMPLEMENT_CLASS(wxAuiManager, wxEvtHandler); const int auiToolBarLayer = 10; -#ifndef __WXGTK__ - - -class wxPseudoTransparentFrame : public wxFrame -{ -public: - wxPseudoTransparentFrame(wxWindow* parent = nullptr, - wxWindowID id = wxID_ANY, - const wxString& title = wxEmptyString, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_FRAME_STYLE, - const wxString &name = wxT("frame")) - : wxFrame(parent, id, title, pos, size, style | wxFRAME_SHAPED, name) - { - SetBackgroundStyle(wxBG_STYLE_PAINT); - m_amount=0; - m_maxWidth=0; - m_maxHeight=0; - m_lastWidth=0; - m_lastHeight=0; - m_canSetShape = true; - m_region = wxRegion(0, 0, 0, 0); - SetTransparent(0); - } - - virtual bool SetTransparent(wxByte alpha) override - { - if (m_canSetShape) - { - wxSize size = GetClientSize(); - - m_maxWidth = size.x; - m_maxHeight = size.y; - m_amount = alpha; - m_region.Clear(); -// m_region.Union(0, 0, 1, m_maxWidth); - if (m_amount) - { - for (int y=0; yAddChild(this); - - g_signal_connect( m_widget, "realize", - G_CALLBACK (gtk_pseudo_window_realized_callback), this ); - - m_backgroundColour.Set(128, 192, 255); - GTKApplyWidgetStyle(); - } - - bool SetTransparent(wxByte WXUNUSED(alpha)) override - { - return true; - } - -protected: - virtual void DoSetSizeHints( int minW, int minH, - int maxW, int maxH, - int incW, int incH) override - { - // the real wxFrame method doesn't work for us because we're not really - // a top level window so skip it - wxWindow::DoSetSizeHints(minW, minH, maxW, maxH, incW, incH); - } - -private: - wxDECLARE_DYNAMIC_CLASS(wxPseudoTransparentFrame); -}; - -wxIMPLEMENT_DYNAMIC_CLASS(wxPseudoTransparentFrame, wxFrame); - -#endif // !__WXGTK__/__WXGTK__ - - - // -- static utility functions -- +static wxBitmap wxCreateVenetianBlindsBitmap(wxByte r, wxByte g, wxByte b, wxByte a) +{ + unsigned char data[] = { r,g,b, 0,0,0, r,g,b }; + unsigned char alpha[] = { a, 128, a }; + + wxImage img(1,3,data,true); + img.SetAlpha(alpha,true); + return wxBitmap(img); +} + static wxBitmap wxPaneCreateStippleBitmap() { // Notice that wxOverlay, under wxMSW, uses the wxBLACK colour i.e.(0,0,0) @@ -586,12 +404,13 @@ wxAuiManager::wxAuiManager(wxWindow* managed_wnd, unsigned int flags) m_actionWindow = nullptr; m_hoverButton = nullptr; m_art = new wxAuiDefaultDockArt; - m_hintWnd = nullptr; m_flags = flags; m_hasMaximized = false; m_frame = nullptr; m_dockConstraintX = 0.3; m_dockConstraintY = 0.3; + m_hintFadeMax = 128; + m_reserved = nullptr; m_currentDragItem = -1; @@ -736,22 +555,8 @@ wxAuiDockUIPart* wxAuiManager::HitTest(int x, int y) // options which are global to wxAuiManager void wxAuiManager::SetFlags(unsigned int flags) { - // find out if we have to call UpdateHintWindowConfig() - bool update_hint_wnd = false; - unsigned int hint_mask = wxAUI_MGR_TRANSPARENT_HINT | - wxAUI_MGR_VENETIAN_BLINDS_HINT | - wxAUI_MGR_RECTANGLE_HINT; - if ((flags & hint_mask) != (m_flags & hint_mask)) - update_hint_wnd = true; - - // set the new flags m_flags = flags; - - if (update_hint_wnd) - { - UpdateHintWindowConfig(); - } } unsigned int wxAuiManager::GetFlags() const @@ -766,8 +571,7 @@ unsigned int wxAuiManager::GetFlags() const bool wxAuiManager::HasLiveResize() const { - return AlwaysUsesLiveResize(m_frame) || - (GetFlags() & wxAUI_MGR_LIVE_RESIZE) == wxAUI_MGR_LIVE_RESIZE; + return (GetFlags() & wxAUI_MGR_LIVE_RESIZE) == wxAUI_MGR_LIVE_RESIZE; } // don't use these anymore as they are deprecated @@ -800,79 +604,6 @@ wxAuiManager* wxAuiManager::GetManager(wxWindow* window) } -void wxAuiManager::UpdateHintWindowConfig() -{ - // find out if the system can do transparent frames - bool can_do_transparent = false; - - wxWindow* w = m_frame; - while (w) - { - if (wxDynamicCast(w, wxFrame)) - { - wxFrame* f = static_cast(w); - can_do_transparent = f->CanSetTransparent(); - - break; - } - - w = w->GetParent(); - } - - // if there is an existing hint window, delete it - if (m_hintWnd) - { - m_hintWnd->Destroy(); - m_hintWnd = nullptr; - } - - m_hintFadeMax = 50; - m_hintWnd = nullptr; - - if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) && can_do_transparent) - { - // Make a window to use for a transparent hint - m_hintWnd = new wxFrame(m_frame, wxID_ANY, wxEmptyString, - wxDefaultPosition, wxSize(1,1), - wxFRAME_TOOL_WINDOW | - wxFRAME_FLOAT_ON_PARENT | - wxFRAME_NO_TASKBAR | - wxNO_BORDER); - #ifdef __WXMAC__ - // Do nothing so this event isn't handled in the base handlers. - - // Letting the hint window activate without this handler can lead to - // weird behaviour on Mac where the menu is switched out to the top - // window's menu in MDI applications when it shouldn't be. So since - // we don't want user interaction with the hint window anyway, we just - // prevent it from activating here. - m_hintWnd->Bind(wxEVT_ACTIVATE, [](wxActivateEvent&) {}); - #endif - - m_hintWnd->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HOTLIGHT)); - } - else - { - if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) != 0 || - (m_flags & wxAUI_MGR_VENETIAN_BLINDS_HINT) != 0) - { - // system can't support transparent fade, or the venetian - // blinds effect was explicitly requested - m_hintWnd = new wxPseudoTransparentFrame(m_frame, - wxID_ANY, - wxEmptyString, - wxDefaultPosition, - wxSize(1,1), - wxFRAME_TOOL_WINDOW | - wxFRAME_FLOAT_ON_PARENT | - wxFRAME_NO_TASKBAR | - wxNO_BORDER); - m_hintFadeMax = 128; - } - } -} - - // SetManagedWindow() is usually called once when the frame // manager class is being initialized. "frame" specifies // the frame which should be managed by the frame manager @@ -913,8 +644,6 @@ void wxAuiManager::SetManagedWindow(wxWindow* wnd) } #endif - - UpdateHintWindowConfig(); } @@ -3269,10 +2998,9 @@ bool wxAuiManager::DoDrop(wxAuiDockInfoArray& docks, return false; } - void wxAuiManager::OnHintFadeTimer(wxTimerEvent& WXUNUSED(event)) { - if (!m_hintWnd || m_hintFadeAmt >= m_hintFadeMax) + if (m_hintFadeAmt >= m_hintFadeMax) { m_hintFadeTimer.Stop(); Unbind(wxEVT_TIMER, &wxAuiManager::OnHintFadeTimer, this, @@ -3281,132 +3009,114 @@ void wxAuiManager::OnHintFadeTimer(wxTimerEvent& WXUNUSED(event)) } m_hintFadeAmt++; - m_hintWnd->SetTransparent(m_hintFadeAmt); + + ShowHint(m_lastHint); } void wxAuiManager::ShowHint(const wxRect& rect) { - if (m_hintWnd) + wxClientDC dc(m_frame); + wxDCOverlay overlaydc(m_overlay, &dc); + overlaydc.Clear(); + + wxDCClipper clip(dc, rect); + + if ( m_flags & wxAUI_MGR_RECTANGLE_HINT ) { - // if the hint rect is the same as last time, don't do anything - if (m_lastHint == rect) - return; - m_lastHint = rect; - - // Decide if we want to fade in the hint and set it to the end value if - // we don't. - if ((m_flags & wxAUI_MGR_HINT_FADE) - && !((m_flags & wxAUI_MGR_VENETIAN_BLINDS_HINT) && - (m_flags & wxAUI_MGR_NO_VENETIAN_BLINDS_FADE)) - ) - m_hintFadeAmt = 0; - else - m_hintFadeAmt = m_hintFadeMax; - - m_hintWnd->SetSize(rect); - m_hintWnd->SetTransparent(m_hintFadeAmt); - - if (!m_hintWnd->IsShown()) - m_hintWnd->Show(); - - // if we are dragging a floating pane, set the focus - // back to that floating pane (otherwise it becomes unfocused) - if (m_action == actionDragFloatingPane && m_actionWindow) - m_actionWindow->SetFocus(); - - m_hintWnd->Raise(); - - - if (m_hintFadeAmt != m_hintFadeMax) // Only fade if we need to - { - // start fade in timer - m_hintFadeTimer.SetOwner(this); - m_hintFadeTimer.Start(15); - Bind(wxEVT_TIMER, &wxAuiManager::OnHintFadeTimer, this, - m_hintFadeTimer.GetId()); - } - } - else // Not using a transparent hint window... - { - if (!(m_flags & wxAUI_MGR_RECTANGLE_HINT)) - return; - - if (m_lastHint != rect) - { - // remove the last hint rectangle - m_lastHint = rect; - m_frame->Refresh(); - m_frame->Update(); - } - - wxScreenDC screendc; - wxRegion clip(1, 1, 10000, 10000); - - // clip all floating windows, so we don't draw over them - int i, pane_count; - for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) - { - wxAuiPaneInfo& pane = m_panes.Item(i); - - if (pane.IsFloating() && - pane.frame && - pane.frame->IsShown()) - { - wxRect r = pane.frame->GetRect(); -#ifdef __WXGTK__ - // wxGTK returns the client size, not the whole frame size - r.width += pane.frame->FromDIP(15); - r.height += pane.frame->FromDIP(35); - r.Inflate(pane.frame->FromDIP(wxSize(5, 5))); -#endif - - clip.Subtract(r); - } - } - - // As we can only hide the hint by redrawing the managed window, we - // need to clip the region to the managed window too or we get - // nasty redrawn problems. - clip.Intersect(m_frame->GetRect()); - - screendc.SetDeviceClippingRegion(clip); - + // Not using a transparent hint window... wxBitmap stipple = wxPaneCreateStippleBitmap(); wxBrush brush(stipple); - screendc.SetBrush(brush); - screendc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(brush); + dc.SetPen(*wxTRANSPARENT_PEN); - screendc.DrawRectangle(rect.x, rect.y, m_frame->FromDIP(5), rect.height); - screendc.DrawRectangle(rect.x + m_frame->FromDIP(5), rect.y, rect.width - m_frame->FromDIP(10), m_frame->FromDIP(5)); - screendc.DrawRectangle(rect.x + rect.width - m_frame->FromDIP(5), rect.y, m_frame->FromDIP(5), rect.height); - screendc.DrawRectangle(rect.x + m_frame->FromDIP(5), rect.y + rect.height - m_frame->FromDIP(5), rect.width - m_frame->FromDIP(10), m_frame->FromDIP(5)); + const int d = m_frame->FromDIP(5); + const int dd = m_frame->FromDIP(10); + + dc.DrawRectangle(rect.x, rect.y, d, rect.height); + dc.DrawRectangle(rect.x + d, rect.y, rect.width - dd, d); + dc.DrawRectangle(rect.x + rect.width - d, rect.y, d, rect.height); + dc.DrawRectangle(rect.x + d, rect.y + rect.height - d, rect.width - dd, d); + + return; + } + +#ifdef __WXGTK3__ + // The standard DC under wxGTK3 supports alpha drawing, whether the overlay + // is native (Wayland) or generic (X11). + const bool canDrawTransparentHint = true; +#else + const bool canDrawTransparentHint = m_overlay.IsNative(); +#endif + + const auto hintCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HOTLIGHT); + const unsigned char r = hintCol.GetRed(); + const unsigned char g = hintCol.GetGreen(); + const unsigned char b = hintCol.GetBlue(); + const unsigned char a = m_hintFadeAmt; + + const auto makeBrush = [=]() + { + return (m_flags & wxAUI_MGR_VENETIAN_BLINDS_HINT) != 0 + ? wxCreateVenetianBlindsBitmap(r, g, b, a) + : wxBrush(wxColour(r, g, b, a)); + }; + + if ( canDrawTransparentHint ) + { +#ifdef __WXMSW__ + m_overlay.SetOpacity(m_hintFadeAmt); +#endif // __WXMSW__ + + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(makeBrush()); + dc.DrawRectangle(rect); + } + else + { + wxBitmap bmp(rect.GetSize(), 32); + wxMemoryDC mdc(bmp); + mdc.Blit(0, 0, rect.width, rect.height, &dc, rect.x, rect.y); + wxRasterOperationMode logicalFunc = wxINVERT; + +#if wxUSE_GRAPHICS_CONTEXT + { + wxGCDC gdc(mdc); + gdc.SetPen(*wxTRANSPARENT_PEN); + gdc.SetBrush(makeBrush()); + gdc.DrawRectangle(wxPoint(0, 0), rect.GetSize()); + } + + logicalFunc = wxCOPY; +#endif // wxUSE_GRAPHICS_CONTEXT + + dc.Blit(rect.x, rect.y, rect.width, rect.height, &mdc, 0, 0, logicalFunc); + } + + // if we are dragging a floating pane, set the focus + // back to that floating pane (otherwise it becomes unfocused) + if (m_action == actionDragFloatingPane && m_actionWindow) + m_actionWindow->SetFocus(); + + if (m_hintFadeAmt != m_hintFadeMax) // Only fade if we need to + { + // start fade in timer + m_hintFadeTimer.SetOwner(this); + m_hintFadeTimer.Start(10); + Bind(wxEVT_TIMER, &wxAuiManager::OnHintFadeTimer, this, + m_hintFadeTimer.GetId()); } } void wxAuiManager::HideHint() { - // hides a transparent window hint, if there is one - if (m_hintWnd) - { - if (m_hintWnd->IsShown()) - m_hintWnd->Show(false); - m_hintWnd->SetTransparent(0); - m_hintFadeTimer.Stop(); - // In case this is called while a hint fade is going, we need to - // disconnect the event handler. - Unbind(wxEVT_TIMER, &wxAuiManager::OnHintFadeTimer, this, - m_hintFadeTimer.GetId()); - m_lastHint = wxRect(); - return; - } + m_overlay.Reset(); + m_hintFadeTimer.Stop(); + // In case this is called while a hint fade is going, we need to + // disconnect the event handler. + Unbind(wxEVT_TIMER, &wxAuiManager::OnHintFadeTimer, this, + m_hintFadeTimer.GetId()); - // hides a painted hint by redrawing the frame window - if (!m_lastHint.IsEmpty()) - { - m_frame->Refresh(); - m_frame->Update(); - m_lastHint = wxRect(); - } + m_lastHint = wxRect(); } @@ -3445,7 +3155,7 @@ void wxAuiManager::StartPaneDrag(wxWindow* pane_window, // first calls DoDrop() to determine the exact position the pane would // be at were if dropped. If the pane would indeed become docked at the // specified drop point, the rectangle hint will be returned in -// screen coordinates. Otherwise, an empty rectangle is returned. +// client coordinates. Otherwise, an empty rectangle is returned. // |pane_window| is the window pointer of the pane being dragged, |pt| is // the mouse position, in client coordinates. |offset| describes the offset // that the mouse is from the upper-left corner of the item being dragged @@ -3516,18 +3226,15 @@ wxRect wxAuiManager::CalculateHintRect(wxWindow* pane_window, delete sizer; - if (rect.IsEmpty()) + if ( !rect.IsEmpty() ) { - return rect; - } + rect.Offset( m_frame->GetClientAreaOrigin() ); - // actually show the hint rectangle on the screen - m_frame->ClientToScreen(&rect.x, &rect.y); - - if ( m_frame->GetLayoutDirection() == wxLayout_RightToLeft ) - { - // Mirror rectangle in RTL mode - rect.x -= rect.GetWidth(); + if ( m_frame->GetLayoutDirection() == wxLayout_RightToLeft ) + { + // Mirror rectangle in RTL mode + rect.x -= rect.GetWidth(); + } } return rect; @@ -3547,10 +3254,22 @@ void wxAuiManager::DrawHintRect(wxWindow* pane_window, { HideHint(); } - else + else if (m_lastHint != rect) // if the hint rect is the same as last time, don't do anything { - ShowHint(rect); - } + m_lastHint = rect; + + // Decide if we want to fade in the hint and set it to the end value if + // we don't. + if ((m_flags & wxAUI_MGR_HINT_FADE) + && !((m_flags & wxAUI_MGR_VENETIAN_BLINDS_HINT) && + (m_flags & wxAUI_MGR_NO_VENETIAN_BLINDS_FADE)) + ) + m_hintFadeAmt = 0; + else + m_hintFadeAmt = m_hintFadeMax; + + ShowHint(rect); + } } void wxAuiManager::OnFloatingPaneMoveStart(wxWindow* wnd) @@ -3886,7 +3605,7 @@ void wxAuiManager::Repaint(wxDC* dc) // make a client dc if (!dc) { - if ( AlwaysUsesLiveResize(m_frame) ) + if ( !wxClientDC::CanBeUsedForDrawing(m_frame) ) { // We can't use wxClientDC in these ports. m_frame->Refresh() ;