Allow better control over splitter position on resize

Add an event which can be handled by the application to determine the
splitter position when the splitter window itself is resized.

This can be used to e.g. preserve the splitter at the given proportion
of the window (and not just in the middle, as it would be already
possible by using gravity 0.5).

Closes #22035.
This commit is contained in:
Gerhard Gruber
2022-01-20 23:12:52 +01:00
committed by Vadim Zeitlin
parent 8f58562fea
commit 1533026945
4 changed files with 129 additions and 10 deletions

View File

@@ -323,9 +323,13 @@ public:
{
SetEventObject(splitter);
if (splitter) m_id = splitter->GetId();
m_data.resize.oldSize = 0;
m_data.resize.newSize = 0;
}
wxSplitterEvent(const wxSplitterEvent& event)
: wxNotifyEvent(event), m_data(event.m_data) { }
: wxNotifyEvent(event), m_data(event.m_data)
{ }
// SASH_POS_CHANGED methods
@@ -334,17 +338,41 @@ public:
void SetSashPosition(int pos)
{
wxASSERT( GetEventType() == wxEVT_SPLITTER_SASH_POS_CHANGED
|| GetEventType() == wxEVT_SPLITTER_SASH_POS_CHANGING);
|| GetEventType() == wxEVT_SPLITTER_SASH_POS_CHANGING
|| GetEventType() == wxEVT_SPLITTER_SASH_POS_RESIZE);
m_data.pos = pos;
m_data.resize.pos = pos;
}
int GetSashPosition() const
{
wxASSERT( GetEventType() == wxEVT_SPLITTER_SASH_POS_CHANGED
|| GetEventType() == wxEVT_SPLITTER_SASH_POS_CHANGING);
|| GetEventType() == wxEVT_SPLITTER_SASH_POS_CHANGING
|| GetEventType() == wxEVT_SPLITTER_SASH_POS_RESIZE);
return m_data.pos;
return m_data.resize.pos;
}
void SetSize(int oldSize, int newSize)
{
wxASSERT(GetEventType() == wxEVT_SPLITTER_SASH_POS_RESIZE);
m_data.resize.oldSize = oldSize;
m_data.resize.newSize = newSize;
}
int GetOldSize() const
{
wxASSERT(GetEventType() == wxEVT_SPLITTER_SASH_POS_RESIZE);
return m_data.resize.oldSize;
}
int GetNewSize() const
{
wxASSERT(GetEventType() == wxEVT_SPLITTER_SASH_POS_RESIZE);
return m_data.resize.newSize;
}
// UNSPLIT event methods
@@ -378,7 +406,12 @@ private:
// data for the different types of event
union
{
int pos; // position for SASH_POS_CHANGED event
struct
{
int pos; // position for SASH_POS_* events
int oldSize; // window size for SASH_POS_UPDATE event
int newSize; // window size for SASH_POS_UPDATE event
} resize;
wxWindow *win; // window being removed for UNSPLIT event
struct
{
@@ -403,6 +436,9 @@ typedef void (wxEvtHandler::*wxSplitterEventFunction)(wxSplitterEvent&);
#define EVT_SPLITTER_SASH_POS_CHANGING(id, fn) \
wx__DECLARE_SPLITTEREVT(SASH_POS_CHANGING, id, fn)
#define EVT_SPLITTER_SASH_POS_RESIZE(id, fn) \
wx__DECLARE_SPLITTEREVT(SASH_POS_UPDATE, id, fn)
#define EVT_SPLITTER_DCLICK(id, fn) \
wx__DECLARE_SPLITTEREVT(DOUBLECLICKED, id, fn)

View File

@@ -32,6 +32,7 @@ class WXDLLIMPEXP_FWD_CORE wxSplitterEvent;
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_SPLITTER_SASH_POS_CHANGED, wxSplitterEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_SPLITTER_SASH_POS_CHANGING, wxSplitterEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_SPLITTER_SASH_POS_RESIZE, wxSplitterEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_SPLITTER_DOUBLECLICKED, wxSplitterEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_SPLITTER_UNSPLIT, wxSplitterEvent );

View File

@@ -68,6 +68,17 @@ enum
May be used to modify the position of the tracking bar to properly
reflect the position that would be set if the drag were to be completed
at this point. Processes a @c wxEVT_SPLITTER_SASH_POS_CHANGING event.
@event{EVT_SPLITTER_SASH_POS_RESIZE(id, func)}
The sash position is in the process of being updated.
May be used to modify the position of the tracking bar to properly
reflect the position that would be set if the update were to be completed.
This can happen e.g. when the window is resized and the sash is moved
according to the gravity setting.
This event is sent when the window is resized and allows the application to select
the desired new sash position. If it doesn't process the event, the position
is determined by the gravity setting.
Processes a @c wxEVT_SPLITTER_SASH_POS_RESIZE event and is only
available in wxWidgets 3.1.6 or newer.
@event{EVT_SPLITTER_SASH_POS_CHANGED(id, func)}
The sash position was changed. May be used to modify the sash position
before it is set, or to prevent the change from taking place.
@@ -514,7 +525,8 @@ public:
Returns the new sash position.
May only be called while processing
@c wxEVT_SPLITTER_SASH_POS_CHANGING and
@c wxEVT_SPLITTER_SASH_POS_CHANGING,
@c wxEVT_SPLITTER_SASH_POS_RESIZE and
@c wxEVT_SPLITTER_SASH_POS_CHANGED events.
*/
int GetSashPosition() const;
@@ -553,17 +565,62 @@ public:
the event handler code to prevent repositioning.
May only be called while processing
@c wxEVT_SPLITTER_SASH_POS_CHANGING and
@c wxEVT_SPLITTER_SASH_POS_CHANGING,
@c wxEVT_SPLITTER_SASH_POS_RESIZE and
@c wxEVT_SPLITTER_SASH_POS_CHANGED events.
@param pos
New sash position.
*/
void SetSashPosition(int pos);
/**
Sets the size values of the window size. This size
is adjusted to the sash orientation.
For a vertical sash it should be the width and for
a horizontal sash it's the height.
May only be called while processing
@c wxEVT_SPLITTER_SASH_POS_CHANGING,
@c wxEVT_SPLITTER_SASH_POS_RESIZE and
@c wxEVT_SPLITTER_SASH_POS_CHANGED events.
@since 3.1.6
*/
void SetSize(int oldSize, int newSize);
/**
Returns the old size before the update. The size value
is already adjusted to the orientation of the sash. So
for a vertical sash it's the width and for a horizontal
sash it's the height.
May only be called while processing
@c wxEVT_SPLITTER_SASH_POS_CHANGING,
@c wxEVT_SPLITTER_SASH_POS_RESIZE and
@c wxEVT_SPLITTER_SASH_POS_CHANGED events.
@since 3.1.6
*/
int GetOldSize() const
/**
Returns the new size which is set after the update.
The size value is already adjusted to the orientation
of the sash. So for a vertical sash it's the width
and for a horizontal sash it's the height.
May only be called while processing
@c wxEVT_SPLITTER_SASH_POS_CHANGING,
@c wxEVT_SPLITTER_SASH_POS_RESIZE and
@c wxEVT_SPLITTER_SASH_POS_CHANGED events.
@since 3.1.6
*/
int GetNewSize() const;
};
wxEventType wxEVT_SPLITTER_SASH_POS_CHANGED;
wxEventType wxEVT_SPLITTER_SASH_POS_CHANGING;
wxEventType wxEVT_SPLITTER_SASH_POS_RESIZE;
wxEventType wxEVT_SPLITTER_DOUBLECLICKED;
wxEventType wxEVT_SPLITTER_UNSPLIT;

View File

@@ -41,6 +41,7 @@
wxDEFINE_EVENT( wxEVT_SPLITTER_SASH_POS_CHANGED, wxSplitterEvent );
wxDEFINE_EVENT( wxEVT_SPLITTER_SASH_POS_CHANGING, wxSplitterEvent );
wxDEFINE_EVENT( wxEVT_SPLITTER_SASH_POS_RESIZE, wxSplitterEvent);
wxDEFINE_EVENT( wxEVT_SPLITTER_DOUBLECLICKED, wxSplitterEvent );
wxDEFINE_EVENT( wxEVT_SPLITTER_UNSPLIT, wxSplitterEvent );
@@ -471,6 +472,8 @@ void wxSplitterWindow::OnSize(wxSizeEvent& event)
// Apply gravity if we use it.
int delta = (int) ( (size - old_size)*m_sashGravity );
// If delta == 0 then sash will be set according to the windows min size.
if ( delta != 0 )
{
newPosition = m_sashPosition + delta;
@@ -478,6 +481,28 @@ void wxSplitterWindow::OnSize(wxSizeEvent& event)
newPosition = m_minimumPaneSize;
}
// Send an event with the newly calculated position. The handler
// can then override the new position by setting the new position.
wxSplitterEvent update(wxEVT_SPLITTER_SASH_POS_RESIZE, this);
update.m_data.resize.pos = newPosition;
update.m_data.resize.oldSize = old_size;
update.m_data.resize.newSize = size;
if (!DoSendEvent(update))
{
// the event handler vetoed the change
newPosition = -1;
}
else
{
// If the user set the sashposition to -1
// we keep the already calculated value,
// otherwise the user provided the new position.
int userPos = update.GetSashPosition();
if (userPos != -1)
newPosition = userPos;
}
// Also check if the second window became too small.
newPosition = AdjustSashPosition(newPosition == -1
? m_sashPosition
@@ -669,7 +694,7 @@ void wxSplitterWindow::SetSashPositionAndNotify(int sashPos)
DoSetSashPosition(sashPos);
wxSplitterEvent event(wxEVT_SPLITTER_SASH_POS_CHANGED, this);
event.m_data.pos = m_sashPosition;
event.m_data.resize.pos = m_sashPosition;
(void)DoSendEvent(event);
}
@@ -1005,7 +1030,7 @@ int wxSplitterWindow::OnSashPositionChanging(int newSashPosition)
// FIXME: shouldn't we do it before the adjustments above so as to ensure
// that the sash position is always reasonable?
wxSplitterEvent event(wxEVT_SPLITTER_SASH_POS_CHANGING, this);
event.m_data.pos = newSashPosition;
event.m_data.resize.pos = newSashPosition;
if ( !DoSendEvent(event) )
{