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.
This commit is contained in:
ali kettab 2024-01-25 03:10:23 +01:00 committed by AliKet
parent fafc714057
commit a38175885c
4 changed files with 44 additions and 70 deletions

View file

@ -12,6 +12,7 @@
#include "wx/window.h" // base class declaration #include "wx/window.h" // base class declaration
#include "wx/containr.h" // wxControlContainer #include "wx/containr.h" // wxControlContainer
#include "wx/overlay.h"
class WXDLLIMPEXP_FWD_CORE wxSplitterEvent; class WXDLLIMPEXP_FWD_CORE wxSplitterEvent;
@ -131,9 +132,6 @@ public:
// Is the window split? // Is the window split?
bool IsSplit() const { return (m_windowTwo != nullptr); } bool IsSplit() const { return (m_windowTwo != nullptr); }
// Return true if wxSP_LIVE_UPDATE is always used.
bool AlwaysUsesLiveUpdate() const;
// Sets the border size // Sets the border size
void SetBorderSize(int WXUNUSED(width)) { } void SetBorderSize(int WXUNUSED(width)) { }
@ -293,7 +291,7 @@ protected:
int m_minimumPaneSize; int m_minimumPaneSize;
wxCursor m_sashCursorWE; wxCursor m_sashCursorWE;
wxCursor m_sashCursorNS; wxCursor m_sashCursorNS;
wxPen *m_sashTrackerPen; wxOverlay m_overlay;
// when in live mode, set this to true to resize children in idle // when in live mode, set this to true to resize children in idle
bool m_needUpdating:1; bool m_needUpdating:1;

View file

@ -142,20 +142,6 @@ public:
*/ */
virtual ~wxSplitterWindow(); 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. Creation function, for two-step construction.
See wxSplitterWindow() for details. See wxSplitterWindow() for details.

View file

@ -254,7 +254,7 @@ MyFrame::MyFrame()
"Toggle sash invisibility"); "Toggle sash invisibility");
splitMenu->AppendSeparator(); splitMenu->AppendSeparator();
auto itemLive = splitMenu->AppendCheckItem(SPLIT_LIVE, splitMenu->AppendCheckItem(SPLIT_LIVE,
"&Live update\tCtrl-L", "&Live update\tCtrl-L",
"Toggle live update mode"); "Toggle live update mode");
splitMenu->AppendCheckItem(SPLIT_BORDER, splitMenu->AppendCheckItem(SPLIT_BORDER,
@ -306,12 +306,6 @@ MyFrame::MyFrame()
menuBar->Check(SPLIT_LIVE, true); menuBar->Check(SPLIT_LIVE, true);
m_splitter = new MySplitterWindow(this); 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 // 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 // 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 // huge amount when it's resized from its initial default size to its real

View file

@ -69,19 +69,34 @@ wxBEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow)
#endif // wxMSW #endif // wxMSW
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
bool wxSplitterWindow::AlwaysUsesLiveUpdate() const
{
return !wxClientDC::CanBeUsedForDrawing(this);
}
static bool IsLive(wxSplitterWindow* wnd) static bool IsLive(wxSplitterWindow* wnd)
{ {
// with wxSP_LIVE_UPDATE style the splitter windows are always resized // with wxSP_LIVE_UPDATE style the splitter windows are always resized
// following the mouse movement while it drags the sash, without it we only // 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 // 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, // dragging is finished
// so check if we can use it and always use live resizing if we can't return wnd->HasFlag(wxSP_LIVE_UPDATE);
return wnd->AlwaysUsesLiveUpdate() || 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, bool wxSplitterWindow::Create(wxWindow *parent, wxWindowID id,
@ -134,7 +149,6 @@ void wxSplitterWindow::Init()
m_minimumPaneSize = 0; m_minimumPaneSize = 0;
m_sashCursorWE = wxCursor(wxCURSOR_SIZEWE); m_sashCursorWE = wxCursor(wxCURSOR_SIZEWE);
m_sashCursorNS = wxCursor(wxCURSOR_SIZENS); m_sashCursorNS = wxCursor(wxCURSOR_SIZENS);
m_sashTrackerPen = new wxPen(*wxBLACK, 2, wxPENSTYLE_SOLID);
m_needUpdating = false; m_needUpdating = false;
m_isHot = false; m_isHot = false;
@ -142,7 +156,6 @@ void wxSplitterWindow::Init()
wxSplitterWindow::~wxSplitterWindow() wxSplitterWindow::~wxSplitterWindow()
{ {
delete m_sashTrackerPen;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -280,10 +293,10 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
return; return;
} }
// Erase old tracker // Hide sash tracker
if ( !isLive ) if ( !isLive )
{ {
DrawSashTracker(m_oldX, m_oldY); m_overlay.Reset();
} }
// the position of the click doesn't exactly correspond to // the position of the click doesn't exactly correspond to
@ -361,9 +374,6 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
m_sashPositionCurrent = posSashNew; m_sashPositionCurrent = posSashNew;
// Erase old tracker
DrawSashTracker(m_oldX, m_oldY);
m_oldX = (m_splitMode == wxSPLIT_VERTICAL ? m_sashPositionCurrent : x); m_oldX = (m_splitMode == wxSPLIT_VERTICAL ? m_sashPositionCurrent : x);
m_oldY = (m_splitMode != wxSPLIT_VERTICAL ? m_sashPositionCurrent : y); m_oldY = (m_splitMode != wxSPLIT_VERTICAL ? m_sashPositionCurrent : y);
@ -380,7 +390,6 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
m_oldY = 0; m_oldY = 0;
#endif // __WXMSW__ #endif // __WXMSW__
// Draw new one
DrawSashTracker(m_oldX, m_oldY); DrawSashTracker(m_oldX, m_oldY);
} }
else else
@ -414,10 +423,10 @@ void wxSplitterWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(even
SetCursor(* wxSTANDARD_CURSOR); SetCursor(* wxSTANDARD_CURSOR);
// Erase old tracker // Erase sash tracker
if ( !IsLive(this) ) 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 x1, y1;
int x2, y2; int x2, y2;
const int sashTrackerWidth = GetDefaultSashSize();
if ( m_splitMode == wxSPLIT_VERTICAL ) if ( m_splitMode == wxSPLIT_VERTICAL )
{ {
x1 = x2 = wxClip(x, 0, w) + m_sashTrackerPen->GetWidth()/2; x1 = wxClip(x, 0, w);
y1 = 2; x2 = sashTrackerWidth;
y2 = h-2; y1 = 0;
y2 = h;
} }
else else
{ {
y1 = y2 = wxClip(y, 0, h) + m_sashTrackerPen->GetWidth()/2; y1 = wxClip(y, 0, h);
x1 = 2; y2 = sashTrackerWidth;
x2 = w-2; x1 = 0;
x2 = w;
} }
#if defined(__WXGTK3__)
wxClientDC dc(this); wxClientDC dc(this);
wxDCOverlay overlaydc( m_overlay, &dc );
overlaydc.Clear();
// In the ports with wxGraphicsContext-based wxDC, such as wxGTK3 or wxOSX, const wxRect rect{x1, y1, x2, y2};
// 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);
dc.SetPen(*m_sashTrackerPen); DrawResizeHint(dc, rect);
#endif
dc.SetLogicalFunction(wxINVERT);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawLine(x1, y1, x2, y2);
} }
int wxSplitterWindow::GetWindowSize() const int wxSplitterWindow::GetWindowSize() const