From a38175885c2d3ac224950009cd2c64f0dcf1a8a4 Mon Sep 17 00:00:00 2001 From: ali kettab Date: Thu, 25 Jan 2024 03:10:23 +0100 Subject: [PATCH] Use wxOverlay to show sash feedback in non-live resize mode in wxSplitterWindow Make non-live resizing possible on all supported platforms thanks to wxOverlay. Previously, live resizing was the only supported mode under these platforms: wxMac, wxQt and wxGTK3 under Wayland. Also remove no longer needed function AlwaysUsesLiveUpdate and its documentation. --- include/wx/generic/splitter.h | 6 +-- interface/wx/splitter.h | 14 ------ samples/splitter/splitter.cpp | 8 +--- src/generic/splitter.cpp | 86 +++++++++++++++++------------------ 4 files changed, 44 insertions(+), 70 deletions(-) diff --git a/include/wx/generic/splitter.h b/include/wx/generic/splitter.h index f2fbe2a906..2d632993ac 100644 --- a/include/wx/generic/splitter.h +++ b/include/wx/generic/splitter.h @@ -12,6 +12,7 @@ #include "wx/window.h" // base class declaration #include "wx/containr.h" // wxControlContainer +#include "wx/overlay.h" class WXDLLIMPEXP_FWD_CORE wxSplitterEvent; @@ -131,9 +132,6 @@ public: // Is the window split? bool IsSplit() const { return (m_windowTwo != nullptr); } - // Return true if wxSP_LIVE_UPDATE is always used. - bool AlwaysUsesLiveUpdate() const; - // Sets the border size void SetBorderSize(int WXUNUSED(width)) { } @@ -293,7 +291,7 @@ protected: int m_minimumPaneSize; wxCursor m_sashCursorWE; wxCursor m_sashCursorNS; - wxPen *m_sashTrackerPen; + wxOverlay m_overlay; // when in live mode, set this to true to resize children in idle bool m_needUpdating:1; diff --git a/interface/wx/splitter.h b/interface/wx/splitter.h index 22d564a7ea..4ff835b2ee 100644 --- a/interface/wx/splitter.h +++ b/interface/wx/splitter.h @@ -142,20 +142,6 @@ public: */ virtual ~wxSplitterWindow(); - /** - Returns true if splitter always behaves as if wxSP_LIVE_UPDATE were - specified. - - This function returns true if non-live update mode is not supported and - live update is always used, even if wxSP_LIVE_UPDATE was not explicitly - specified. - - @see wxClientDC::CanBeUsedForDrawing() - - @since 3.3.0 - */ - bool AlwaysUsesLiveUpdate() const; - /** Creation function, for two-step construction. See wxSplitterWindow() for details. diff --git a/samples/splitter/splitter.cpp b/samples/splitter/splitter.cpp index cee9eafc03..3d100be780 100644 --- a/samples/splitter/splitter.cpp +++ b/samples/splitter/splitter.cpp @@ -254,7 +254,7 @@ MyFrame::MyFrame() "Toggle sash invisibility"); splitMenu->AppendSeparator(); - auto itemLive = splitMenu->AppendCheckItem(SPLIT_LIVE, + splitMenu->AppendCheckItem(SPLIT_LIVE, "&Live update\tCtrl-L", "Toggle live update mode"); splitMenu->AppendCheckItem(SPLIT_BORDER, @@ -306,12 +306,6 @@ MyFrame::MyFrame() menuBar->Check(SPLIT_LIVE, true); m_splitter = new MySplitterWindow(this); - if ( m_splitter->AlwaysUsesLiveUpdate() ) - { - // Only live update mode is supported, so this menu item can't be used. - itemLive->Enable(false); - } - // If you use non-zero gravity you must initialize the splitter with its // correct initial size, otherwise it will change the sash position by a // huge amount when it's resized from its initial default size to its real diff --git a/src/generic/splitter.cpp b/src/generic/splitter.cpp index 5636704951..fdc34e879b 100644 --- a/src/generic/splitter.cpp +++ b/src/generic/splitter.cpp @@ -69,19 +69,34 @@ wxBEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow) #endif // wxMSW wxEND_EVENT_TABLE() -bool wxSplitterWindow::AlwaysUsesLiveUpdate() const -{ - return !wxClientDC::CanBeUsedForDrawing(this); -} - static bool IsLive(wxSplitterWindow* wnd) { // with wxSP_LIVE_UPDATE style the splitter windows are always resized // following the mouse movement while it drags the sash, without it we only // draw the sash at the new position but only resize the windows when the - // dragging is finished -- but drawing the sash is done using wxClientDC, - // so check if we can use it and always use live resizing if we can't - return wnd->AlwaysUsesLiveUpdate() || wnd->HasFlag(wxSP_LIVE_UPDATE); + // dragging is finished + return wnd->HasFlag(wxSP_LIVE_UPDATE); +} + +static wxBitmap wxPaneCreateStippleBitmap() +{ + // Notice that wxOverlay, under wxMSW, uses the wxBLACK colour i.e.(0,0,0) + // as the key colour for transparency. and using it for the stipple bitmap + // will make the sash feedback totaly invisible if the window's background + // colour is (192,192,192) or so. (1,1,1) is used instead. + unsigned char data[] = { 1,1,1,192,192,192, 192,192,192,1,1,1 }; + wxImage img(2,2,data,true); + return wxBitmap(img); +} + +static void DrawResizeHint(wxDC& dc, const wxRect& rect) +{ + wxBitmap stipple = wxPaneCreateStippleBitmap(); + wxBrush brush(stipple); + dc.SetBrush(brush); + dc.SetPen(*wxTRANSPARENT_PEN); + + dc.DrawRectangle(rect); } bool wxSplitterWindow::Create(wxWindow *parent, wxWindowID id, @@ -134,7 +149,6 @@ void wxSplitterWindow::Init() m_minimumPaneSize = 0; m_sashCursorWE = wxCursor(wxCURSOR_SIZEWE); m_sashCursorNS = wxCursor(wxCURSOR_SIZENS); - m_sashTrackerPen = new wxPen(*wxBLACK, 2, wxPENSTYLE_SOLID); m_needUpdating = false; m_isHot = false; @@ -142,7 +156,6 @@ void wxSplitterWindow::Init() wxSplitterWindow::~wxSplitterWindow() { - delete m_sashTrackerPen; } // ---------------------------------------------------------------------------- @@ -280,10 +293,10 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) return; } - // Erase old tracker + // Hide sash tracker if ( !isLive ) { - DrawSashTracker(m_oldX, m_oldY); + m_overlay.Reset(); } // the position of the click doesn't exactly correspond to @@ -361,9 +374,6 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) m_sashPositionCurrent = posSashNew; - // Erase old tracker - DrawSashTracker(m_oldX, m_oldY); - m_oldX = (m_splitMode == wxSPLIT_VERTICAL ? m_sashPositionCurrent : x); m_oldY = (m_splitMode != wxSPLIT_VERTICAL ? m_sashPositionCurrent : y); @@ -380,7 +390,6 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) m_oldY = 0; #endif // __WXMSW__ - // Draw new one DrawSashTracker(m_oldX, m_oldY); } else @@ -414,10 +423,10 @@ void wxSplitterWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(even SetCursor(* wxSTANDARD_CURSOR); - // Erase old tracker + // Erase sash tracker if ( !IsLive(this) ) { - DrawSashTracker(m_oldX, m_oldY); + m_overlay.Reset(); } } @@ -612,43 +621,30 @@ void wxSplitterWindow::DrawSashTracker(int x, int y) int x1, y1; int x2, y2; + const int sashTrackerWidth = GetDefaultSashSize(); + if ( m_splitMode == wxSPLIT_VERTICAL ) { - x1 = x2 = wxClip(x, 0, w) + m_sashTrackerPen->GetWidth()/2; - y1 = 2; - y2 = h-2; + x1 = wxClip(x, 0, w); + x2 = sashTrackerWidth; + y1 = 0; + y2 = h; } else { - y1 = y2 = wxClip(y, 0, h) + m_sashTrackerPen->GetWidth()/2; - x1 = 2; - x2 = w-2; + y1 = wxClip(y, 0, h); + y2 = sashTrackerWidth; + x1 = 0; + x2 = w; } -#if defined(__WXGTK3__) wxClientDC dc(this); + wxDCOverlay overlaydc( m_overlay, &dc ); + overlaydc.Clear(); - // In the ports with wxGraphicsContext-based wxDC, such as wxGTK3 or wxOSX, - // wxINVERT only works for inverting the background when using white - // foreground (note that this code is not used anyhow for __WXMAC__ due to - // always using live-resizing there, see IsLive()). - dc.SetPen(*wxWHITE_PEN); -#else - // We need to use wxScreenDC and not wxClientDC at least for wxMSW where - // drawing in this window itself would be hidden by its children windows, - // that cover it almost entirely. - wxScreenDC dc; - ClientToScreen(&x1, &y1); - ClientToScreen(&x2, &y2); + const wxRect rect{x1, y1, x2, y2}; - dc.SetPen(*m_sashTrackerPen); -#endif - - dc.SetLogicalFunction(wxINVERT); - - dc.SetBrush(*wxTRANSPARENT_BRUSH); - - dc.DrawLine(x1, y1, x2, y2); + DrawResizeHint(dc, rect); } int wxSplitterWindow::GetWindowSize() const