various splitter fixes:

1. generate the events from the event handlers, thus it is now possible to
   process the splitter events in the parent window
2. when double clicking the splitter which can't be unsplit it doesn't jump
   by a couple of pixels
3. misc code cleanup


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@14263 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2002-02-16 21:53:52 +00:00
parent 590b1a4d62
commit 3e58dcb905
3 changed files with 120 additions and 109 deletions

View File

@@ -9,6 +9,7 @@ in assert failure (in debug mode) and will return meaningless results.
\wxheading{Derived from} \wxheading{Derived from}
\helpref{wxNotifyEvent}{wxnotifyevent}\\
\helpref{wxCommandEvent}{wxcommandevent}\\ \helpref{wxCommandEvent}{wxcommandevent}\\
\helpref{wxEvent}{wxevent}\\ \helpref{wxEvent}{wxevent}\\
\helpref{wxObject}{wxobject} \helpref{wxObject}{wxobject}
@@ -25,20 +26,23 @@ functions that take a wxSplitterEvent argument.
\twocolwidtha{10cm} \twocolwidtha{10cm}
\begin{twocollist}\itemsep=0pt \begin{twocollist}\itemsep=0pt
\twocolitem{{\bf EVT\_SPLITTER\_SASH\_POS\_CHANGING(id, func)}}{The sash \twocolitem{{\bf EVT\_SPLITTER\_SASH\_POS\_CHANGING(id, func)}}{The sash
position is in the process of being changed. May be used to modify the position is in the process of being changed. You may prevent this change
position of the tracking bar to properly reflect the position that from happening by calling \helpref{Veto}{wxnotifyeventveto} or you may also
would be set if the drag were to be completed at this point. Processes modify the position of the tracking bar to properly reflect the position that
a wxEVT\_COMMAND\_SPLITTER\_SASH\_POS\_CHANGING event.} would be set if the drag were to be completed at this point. Processes a
wxEVT\_COMMAND\_SPLITTER\_SASH\_POS\_CHANGING event.}
\twocolitem{{\bf EVT\_SPLITTER\_SASH\_POS\_CHANGED(id, func)}}{The sash \twocolitem{{\bf EVT\_SPLITTER\_SASH\_POS\_CHANGED(id, func)}}{The sash
position was changed. May be used to modify the sash position before position was changed. May be used to modify the sash position before
it is set, or to prevent the change from taking place. it is set, or to prevent the change from taking place.
Processes a wxEVT\_COMMAND\_SPLITTER\_SASH\_POS\_CHANGED event.} Processes a wxEVT\_COMMAND\_SPLITTER\_SASH\_POS\_CHANGED event.}
\twocolitem{{\bf EVT\_SPLITTER\_UNSPLIT(id, func)}}{The splitter has been just \twocolitem{{\bf EVT\_SPLITTER\_UNSPLIT(id, func)}}{The splitter has been just
unsplit. Processes a wxEVT\_COMMAND\_SPLITTER\_UNSPLIT event.} unsplit. Processes a wxEVT\_COMMAND\_SPLITTER\_UNSPLIT event. This event can't
be vetoed.}
\twocolitem{{\bf EVT\_SPLITTER\_DOUBLECLICKED(id, func)}}{The sash was double \twocolitem{{\bf EVT\_SPLITTER\_DOUBLECLICKED(id, func)}}{The sash was double
clicked. The default behaviour is to unsplit the window when this happens clicked. The default behaviour is to unsplit the window when this happens
(unless the minimum pane size has been set to a value greater than zero). (unless the minimum pane size has been set to a value greater than zero). This
Processes a wxEVT\_COMMAND\_SPLITTER\_DOUBLECLICKED event.} won't happen if you veto this event. Processes a
wxEVT\_COMMAND\_SPLITTER\_DOUBLECLICKED event.}
\end{twocollist}% \end{twocollist}%
\wxheading{See also} \wxheading{See also}

View File

@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: splitter.h // Name: wx/splitter.h
// Purpose: wxSplitterWindow class // Purpose: wxSplitterWindow class
// Author: Julian Smart // Author: Julian Smart
// Modified by: // Modified by:
@@ -154,22 +154,28 @@ public:
void SetMinimumPaneSize(int min); void SetMinimumPaneSize(int min);
int GetMinimumPaneSize() const { return m_minimumPaneSize; } int GetMinimumPaneSize() const { return m_minimumPaneSize; }
// NB: the OnXXX() functions below are for backwards compatibility only,
// don't use them in new code but handle the events instead!
// called when the sash position is about to change, may return a new value
// for the sash or -1 to prevent the change from happening at all
virtual int OnSashPositionChanging(int newSashPosition);
// Called when the sash position is about to be changed, return // Called when the sash position is about to be changed, return
// FALSE from here to prevent the change from taking place. // FALSE from here to prevent the change from taking place.
// Repositions sash to minimum position if pane would be too small. // Repositions sash to minimum position if pane would be too small.
// newSashPosition here is always positive or zero. // newSashPosition here is always positive or zero.
virtual bool OnSashPositionChange(int WXUNUSED(newSashPosition)) virtual bool OnSashPositionChange(int newSashPosition);
{ return TRUE; }
// If the sash is moved to an extreme position, a subwindow // If the sash is moved to an extreme position, a subwindow
// is removed from the splitter window, and the app is // is removed from the splitter window, and the app is
// notified. The app should delete or hide the window. // notified. The app should delete or hide the window.
virtual void OnUnsplit(wxWindow *WXUNUSED(removed)) { } virtual void OnUnsplit(wxWindow *removed);
// Called when the sash is double-clicked. // Called when the sash is double-clicked.
// The default behaviour is to remove the sash if the // The default behaviour is to remove the sash if the
// minimum pane size is zero. // minimum pane size is zero.
virtual void OnDoubleClickSash(int WXUNUSED(x), int WXUNUSED(y)) { } virtual void OnDoubleClickSash(int x, int y);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Implementation // Implementation
@@ -208,14 +214,14 @@ public:
bool GetNeedUpdating() const { return m_needUpdating ; } bool GetNeedUpdating() const { return m_needUpdating ; }
protected: protected:
// our event handlers // event handlers
void OnSashPosChanged(wxSplitterEvent& event); #ifdef __WXMSW__
void OnSashPosChanging(wxSplitterEvent& event);
void OnDoubleClick(wxSplitterEvent& event);
void OnUnsplitEvent(wxSplitterEvent& event);
void OnSetCursor(wxSetCursorEvent& event); void OnSetCursor(wxSetCursorEvent& event);
#endif // wxMSW
void SendUnsplitEvent(wxWindow *winRemoved); // send the given event, return FALSE if the event was processed and vetoed
// by the user code
inline bool DoSendEvent(wxSplitterEvent& event);
protected: protected:
// common part of all ctors // common part of all ctors
@@ -275,12 +281,12 @@ private:
// usual wxWin convention, but the three event types have different kind of // usual wxWin convention, but the three event types have different kind of
// data associated with them, so the accessors can be only used if the real // data associated with them, so the accessors can be only used if the real
// event type matches with the one for which the accessors make sense // event type matches with the one for which the accessors make sense
class WXDLLEXPORT wxSplitterEvent : public wxCommandEvent class WXDLLEXPORT wxSplitterEvent : public wxNotifyEvent
{ {
public: public:
wxSplitterEvent(wxEventType type = wxEVT_NULL, wxSplitterEvent(wxEventType type = wxEVT_NULL,
wxSplitterWindow *splitter = (wxSplitterWindow *)NULL) wxSplitterWindow *splitter = (wxSplitterWindow *)NULL)
: wxCommandEvent(type) : wxNotifyEvent(type)
{ {
SetEventObject(splitter); SetEventObject(splitter);
if (splitter) m_id = splitter->GetId(); if (splitter) m_id = splitter->GetId();

View File

@@ -41,7 +41,7 @@ DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_DOUBLECLICKED)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_UNSPLIT) DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_UNSPLIT)
IMPLEMENT_DYNAMIC_CLASS(wxSplitterWindow, wxWindow) IMPLEMENT_DYNAMIC_CLASS(wxSplitterWindow, wxWindow)
IMPLEMENT_DYNAMIC_CLASS(wxSplitterEvent, wxCommandEvent) IMPLEMENT_DYNAMIC_CLASS(wxSplitterEvent, wxNotifyEvent)
BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow) BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow)
EVT_PAINT(wxSplitterWindow::OnPaint) EVT_PAINT(wxSplitterWindow::OnPaint)
@@ -49,14 +49,9 @@ BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow)
EVT_IDLE(wxSplitterWindow::OnIdle) EVT_IDLE(wxSplitterWindow::OnIdle)
EVT_MOUSE_EVENTS(wxSplitterWindow::OnMouseEvent) EVT_MOUSE_EVENTS(wxSplitterWindow::OnMouseEvent)
#ifdef __WXMSW__
EVT_SET_CURSOR(wxSplitterWindow::OnSetCursor) EVT_SET_CURSOR(wxSplitterWindow::OnSetCursor)
#endif // wxMSW
EVT_SPLITTER_SASH_POS_CHANGED(-1, wxSplitterWindow::OnSashPosChanged)
// NB: we borrow OnSashPosChanged for purposes of
// EVT_SPLITTER_SASH_POS_CHANGING since default implementation is identical
EVT_SPLITTER_SASH_POS_CHANGING(-1, wxSplitterWindow::OnSashPosChanged)
EVT_SPLITTER_DCLICK(-1, wxSplitterWindow::OnDoubleClick)
EVT_SPLITTER_UNSPLIT(-1, wxSplitterWindow::OnUnsplitEvent)
WX_EVENT_TABLE_CONTROL_CONTAINER(wxSplitterWindow) WX_EVENT_TABLE_CONTROL_CONTAINER(wxSplitterWindow)
END_EVENT_TABLE() END_EVENT_TABLE()
@@ -219,52 +214,46 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
DrawSashTracker(m_oldX, m_oldY); DrawSashTracker(m_oldX, m_oldY);
} }
// Obtain window size. We are only interested in the dimension the sash // the position of the click doesn't exactly correspond to
// splits up // m_sashPosition, rather it changes it by the distance by which the
int window_size = GetWindowSize(); // mouse has moved
int new_sash_position = m_splitMode == wxSPLIT_VERTICAL ? x : y; int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY;
wxSplitterEvent eventSplitter(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, int posSashNew = OnSashPositionChanging(m_sashPosition + diff);
this); if ( posSashNew == -1 )
eventSplitter.m_data.pos = new_sash_position;
if ( GetEventHandler()->ProcessEvent(eventSplitter) )
{
new_sash_position = eventSplitter.GetSashPosition();
if ( new_sash_position == -1 )
{ {
// change not allowed // change not allowed
return; return;
} }
}
if ( m_permitUnsplitAlways || m_minimumPaneSize == 0 ) if ( m_permitUnsplitAlways || m_minimumPaneSize == 0 )
{ {
// Deal with possible unsplit scenarios // Deal with possible unsplit scenarios
if ( new_sash_position == 0 ) if ( posSashNew == 0 )
{ {
// We remove the first window from the view // We remove the first window from the view
wxWindow *removedWindow = m_windowOne; wxWindow *removedWindow = m_windowOne;
m_windowOne = m_windowTwo; m_windowOne = m_windowTwo;
m_windowTwo = (wxWindow *) NULL; m_windowTwo = (wxWindow *) NULL;
SendUnsplitEvent(removedWindow); OnUnsplit(removedWindow);
DoSetSashPosition(0); DoSetSashPosition(0);
} }
else if ( new_sash_position == window_size ) else if ( posSashNew == GetWindowSize() )
{ {
// We remove the second window from the view // We remove the second window from the view
wxWindow *removedWindow = m_windowTwo; wxWindow *removedWindow = m_windowTwo;
m_windowTwo = (wxWindow *) NULL; m_windowTwo = (wxWindow *) NULL;
SendUnsplitEvent(removedWindow); OnUnsplit(removedWindow);
DoSetSashPosition(0); DoSetSashPosition(0);
} }
else else
{ {
DoSetSashPosition(new_sash_position); DoSetSashPosition(posSashNew);
} }
} }
else else
{ {
DoSetSashPosition(new_sash_position); DoSetSashPosition(posSashNew);
} }
SizeWindows(); SizeWindows();
@@ -309,26 +298,18 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
{ {
SetCursor(*m_sashCursorNS); SetCursor(*m_sashCursorNS);
} }
#endif #endif // __WXMSW__
// Obtain window size. We are only interested in the dimension the sash int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY;
// splits up
int new_sash_position = m_splitMode == wxSPLIT_VERTICAL ? x : y;
wxSplitterEvent eventSplitter(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, int posSashNew = OnSashPositionChanging(m_sashPosition + diff);
this); if ( posSashNew == -1 )
eventSplitter.m_data.pos = new_sash_position;
if ( GetEventHandler()->ProcessEvent(eventSplitter) )
{
new_sash_position = eventSplitter.GetSashPosition();
if ( new_sash_position == -1 )
{ {
// change not allowed // change not allowed
return; return;
} }
}
if (new_sash_position == m_sashPosition) if ( posSashNew == m_sashPosition )
return; return;
// Erase old tracker // Erase old tracker
@@ -338,9 +319,9 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
} }
if (m_splitMode == wxSPLIT_VERTICAL) if (m_splitMode == wxSPLIT_VERTICAL)
x = new_sash_position; x = posSashNew;
else else
y = new_sash_position; y = posSashNew;
// Remember old positions // Remember old positions
m_oldX = x; m_oldX = x;
@@ -366,18 +347,13 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
} }
else else
{ {
DoSetSashPosition(new_sash_position); DoSetSashPosition(posSashNew);
m_needUpdating = TRUE; m_needUpdating = TRUE;
} }
} }
else if ( event.LeftDClick() ) else if ( event.LeftDClick() )
{ {
wxSplitterEvent eventSplitter(wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, OnDoubleClickSash(x, y);
this);
eventSplitter.m_data.pt.x = x;
eventSplitter.m_data.pt.y = y;
(void)GetEventHandler()->ProcessEvent(eventSplitter);
} }
} }
@@ -743,7 +719,12 @@ int wxSplitterWindow::AdjustSashPosition(int sashPos) const
void wxSplitterWindow::DoSetSashPosition(int sashPos) void wxSplitterWindow::DoSetSashPosition(int sashPos)
{ {
m_requestedSashPosition = sashPos; m_requestedSashPosition = sashPos;
m_sashPosition = (sashPos == 0) ? 0 : AdjustSashPosition(sashPos); m_sashPosition = sashPos == 0 ? 0 : AdjustSashPosition(sashPos);
wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, this);
event.m_data.pos = m_sashPosition;
(void)DoSendEvent(event);
} }
// Position and size subwindows. // Position and size subwindows.
@@ -865,7 +846,7 @@ bool wxSplitterWindow::Unsplit(wxWindow *toRemove)
return FALSE; return FALSE;
} }
SendUnsplitEvent(win); OnUnsplit(win);
DoSetSashPosition(0); DoSetSashPosition(0);
SizeWindows(); SizeWindows();
@@ -951,31 +932,38 @@ void wxSplitterWindow::InitColours()
#endif // __WIN16__ #endif // __WIN16__
} }
void wxSplitterWindow::SendUnsplitEvent(wxWindow *winRemoved) bool wxSplitterWindow::DoSendEvent(wxSplitterEvent& event)
{ {
wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_UNSPLIT, this); return !GetEventHandler()->ProcessEvent(event) || event.IsAllowed();
event.m_data.win = winRemoved;
(void)GetEventHandler()->ProcessEvent(event);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// splitter event handlers // wxSplitterWindow virtual functions: they now just generate the events
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
void wxSplitterWindow::OnSashPosChanged(wxSplitterEvent& event) bool wxSplitterWindow::OnSashPositionChange(int WXUNUSED(newSashPosition))
{
// always allow by default
return TRUE;
}
int wxSplitterWindow::OnSashPositionChanging(int newSashPosition)
{ {
// If within UNSPLIT_THRESHOLD from edge, set to edge to cause closure. // If within UNSPLIT_THRESHOLD from edge, set to edge to cause closure.
const int UNSPLIT_THRESHOLD = 4; const int UNSPLIT_THRESHOLD = 4;
int newSashPosition = event.GetSashPosition(); // first of all, check if OnSashPositionChange() doesn't forbid this change
if ( !OnSashPositionChange(newSashPosition) )
{
// it does
return -1;
}
// Obtain relevant window dimension for bottom / right threshold check // Obtain relevant window dimension for bottom / right threshold check
int window_size = GetWindowSize(); int window_size = GetWindowSize();
bool unsplit_scenario = FALSE; bool unsplit_scenario = FALSE;
if ( m_permitUnsplitAlways if ( m_permitUnsplitAlways || m_minimumPaneSize == 0 )
|| m_minimumPaneSize == 0 )
{ {
// Do edge detection if unsplit premitted // Do edge detection if unsplit premitted
if ( newSashPosition <= UNSPLIT_THRESHOLD ) if ( newSashPosition <= UNSPLIT_THRESHOLD )
@@ -1003,50 +991,61 @@ void wxSplitterWindow::OnSashPosChanged(wxSplitterEvent& event)
if ( newSashPosition < 0 || newSashPosition > window_size ) if ( newSashPosition < 0 || newSashPosition > window_size )
newSashPosition = window_size / 2; newSashPosition = window_size / 2;
// for compatibility, call the virtual function // now let the event handler have it
if ( !OnSashPositionChange(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_COMMAND_SPLITTER_SASH_POS_CHANGING, this);
event.m_data.pos = newSashPosition;
if ( !DoSendEvent(event) )
{ {
// the event handler vetoed the change
newSashPosition = -1; newSashPosition = -1;
} }
else
{
// it could have been changed by it
newSashPosition = event.GetSashPosition();
}
event.SetSashPosition(newSashPosition); return newSashPosition;
} }
// Called when the sash is double-clicked. The default behaviour is to remove // Called when the sash is double-clicked. The default behaviour is to remove
// the sash if the minimum pane size is zero. // the sash if the minimum pane size is zero.
void wxSplitterWindow::OnDoubleClick(wxSplitterEvent& event) void wxSplitterWindow::OnDoubleClickSash(int x, int y)
{
// new code should handle events instead of using the virtual functions
wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, this);
event.m_data.pt.x = x;
event.m_data.pt.y = y;
if ( DoSendEvent(event) )
{ {
// for compatibility, call the virtual function
OnDoubleClickSash(event.GetX(), event.GetY());
if ( GetMinimumPaneSize() == 0 || m_permitUnsplitAlways ) if ( GetMinimumPaneSize() == 0 || m_permitUnsplitAlways )
{ {
Unsplit(); Unsplit();
} }
} }
//else: blocked by user
void wxSplitterWindow::OnUnsplitEvent(wxSplitterEvent& event)
{
wxWindow *win = event.GetWindowBeingRemoved();
// do it before calling OnUnsplit() which may delete the window
win->Show(FALSE);
// for compatibility, call the virtual function
OnUnsplit(win);
} }
#if defined(__WXMSW__) void wxSplitterWindow::OnUnsplit(wxWindow *winRemoved)
#define WXUNUSED_UNLESS_MSW(identifier) identifier
#else
#define WXUNUSED_UNLESS_MSW(identifier) WXUNUSED(identifier)
#endif
void wxSplitterWindow::OnSetCursor(wxSetCursorEvent& WXUNUSED_UNLESS_MSW(event))
{ {
// this is currently called (and needed) under MSW only... // do it before calling the event handler which may delete the window
winRemoved->Show(FALSE);
wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_UNSPLIT, this);
event.m_data.win = winRemoved;
(void)DoSendEvent(event);
}
#ifdef __WXMSW__ #ifdef __WXMSW__
// this is currently called (and needed) under MSW only...
void wxSplitterWindow::OnSetCursor(wxSetCursorEvent& event)
{
// if we don't do it, the resizing cursor might be set for child window: // if we don't do it, the resizing cursor might be set for child window:
// and like this we explicitly say that our cursor should not be used for // and like this we explicitly say that our cursor should not be used for
// children windows which overlap us // children windows which overlap us
@@ -1057,5 +1056,7 @@ void wxSplitterWindow::OnSetCursor(wxSetCursorEvent& WXUNUSED_UNLESS_MSW(event))
event.Skip(); event.Skip();
} }
//else: do nothing, in particular, don't call Skip() //else: do nothing, in particular, don't call Skip()
#endif // wxMSW
} }
#endif // wxMSW