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/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;

View file

@ -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.

View file

@ -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

View file

@ -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