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}
\helpref{wxNotifyEvent}{wxnotifyevent}\\
\helpref{wxCommandEvent}{wxcommandevent}\\
\helpref{wxEvent}{wxevent}\\
\helpref{wxObject}{wxobject}
@@ -25,20 +26,23 @@ functions that take a wxSplitterEvent argument.
\twocolwidtha{10cm}
\begin{twocollist}\itemsep=0pt
\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 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 wxEVT\_COMMAND\_SPLITTER\_SASH\_POS\_CHANGING event.}
position is in the process of being changed. You may prevent this change
from happening by calling \helpref{Veto}{wxnotifyeventveto} or you may also
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
wxEVT\_COMMAND\_SPLITTER\_SASH\_POS\_CHANGING event.}
\twocolitem{{\bf 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.
Processes a wxEVT\_COMMAND\_SPLITTER\_SASH\_POS\_CHANGED event.}
\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
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).
Processes a wxEVT\_COMMAND\_SPLITTER\_DOUBLECLICKED event.}
(unless the minimum pane size has been set to a value greater than zero). This
won't happen if you veto this event. Processes a
wxEVT\_COMMAND\_SPLITTER\_DOUBLECLICKED event.}
\end{twocollist}%
\wxheading{See also}

View File

@@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////
// Name: splitter.h
// Name: wx/splitter.h
// Purpose: wxSplitterWindow class
// Author: Julian Smart
// Modified by:
@@ -154,22 +154,28 @@ public:
void SetMinimumPaneSize(int min);
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
// FALSE from here to prevent the change from taking place.
// Repositions sash to minimum position if pane would be too small.
// newSashPosition here is always positive or zero.
virtual bool OnSashPositionChange(int WXUNUSED(newSashPosition))
{ return TRUE; }
virtual bool OnSashPositionChange(int newSashPosition);
// If the sash is moved to an extreme position, a subwindow
// is removed from the splitter window, and the app is
// 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.
// The default behaviour is to remove the sash if the
// minimum pane size is zero.
virtual void OnDoubleClickSash(int WXUNUSED(x), int WXUNUSED(y)) { }
virtual void OnDoubleClickSash(int x, int y);
////////////////////////////////////////////////////////////////////////////
// Implementation
@@ -208,14 +214,14 @@ public:
bool GetNeedUpdating() const { return m_needUpdating ; }
protected:
// our event handlers
void OnSashPosChanged(wxSplitterEvent& event);
void OnSashPosChanging(wxSplitterEvent& event);
void OnDoubleClick(wxSplitterEvent& event);
void OnUnsplitEvent(wxSplitterEvent& event);
// event handlers
#ifdef __WXMSW__
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:
// common part of all ctors
@@ -275,12 +281,12 @@ private:
// 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
// event type matches with the one for which the accessors make sense
class WXDLLEXPORT wxSplitterEvent : public wxCommandEvent
class WXDLLEXPORT wxSplitterEvent : public wxNotifyEvent
{
public:
wxSplitterEvent(wxEventType type = wxEVT_NULL,
wxSplitterWindow *splitter = (wxSplitterWindow *)NULL)
: wxCommandEvent(type)
: wxNotifyEvent(type)
{
SetEventObject(splitter);
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)
IMPLEMENT_DYNAMIC_CLASS(wxSplitterWindow, wxWindow)
IMPLEMENT_DYNAMIC_CLASS(wxSplitterEvent, wxCommandEvent)
IMPLEMENT_DYNAMIC_CLASS(wxSplitterEvent, wxNotifyEvent)
BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow)
EVT_PAINT(wxSplitterWindow::OnPaint)
@@ -49,14 +49,9 @@ BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow)
EVT_IDLE(wxSplitterWindow::OnIdle)
EVT_MOUSE_EVENTS(wxSplitterWindow::OnMouseEvent)
#ifdef __WXMSW__
EVT_SET_CURSOR(wxSplitterWindow::OnSetCursor)
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)
#endif // wxMSW
WX_EVENT_TABLE_CONTROL_CONTAINER(wxSplitterWindow)
END_EVENT_TABLE()
@@ -219,52 +214,46 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
DrawSashTracker(m_oldX, m_oldY);
}
// Obtain window size. We are only interested in the dimension the sash
// splits up
int window_size = GetWindowSize();
int new_sash_position = m_splitMode == wxSPLIT_VERTICAL ? x : y;
// the position of the click doesn't exactly correspond to
// m_sashPosition, rather it changes it by the distance by which the
// mouse has moved
int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY;
wxSplitterEvent eventSplitter(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED,
this);
eventSplitter.m_data.pos = new_sash_position;
if ( GetEventHandler()->ProcessEvent(eventSplitter) )
int posSashNew = OnSashPositionChanging(m_sashPosition + diff);
if ( posSashNew == -1 )
{
new_sash_position = eventSplitter.GetSashPosition();
if ( new_sash_position == -1 )
{
// change not allowed
return;
}
// change not allowed
return;
}
if ( m_permitUnsplitAlways || m_minimumPaneSize == 0 )
{
// Deal with possible unsplit scenarios
if ( new_sash_position == 0 )
if ( posSashNew == 0 )
{
// We remove the first window from the view
wxWindow *removedWindow = m_windowOne;
m_windowOne = m_windowTwo;
m_windowTwo = (wxWindow *) NULL;
SendUnsplitEvent(removedWindow);
OnUnsplit(removedWindow);
DoSetSashPosition(0);
}
else if ( new_sash_position == window_size )
else if ( posSashNew == GetWindowSize() )
{
// We remove the second window from the view
wxWindow *removedWindow = m_windowTwo;
m_windowTwo = (wxWindow *) NULL;
SendUnsplitEvent(removedWindow);
OnUnsplit(removedWindow);
DoSetSashPosition(0);
}
else
{
DoSetSashPosition(new_sash_position);
DoSetSashPosition(posSashNew);
}
}
else
{
DoSetSashPosition(new_sash_position);
DoSetSashPosition(posSashNew);
}
SizeWindows();
@@ -309,26 +298,18 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
{
SetCursor(*m_sashCursorNS);
}
#endif
#endif // __WXMSW__
// Obtain window size. We are only interested in the dimension the sash
// splits up
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_CHANGING,
this);
eventSplitter.m_data.pos = new_sash_position;
if ( GetEventHandler()->ProcessEvent(eventSplitter) )
int posSashNew = OnSashPositionChanging(m_sashPosition + diff);
if ( posSashNew == -1 )
{
new_sash_position = eventSplitter.GetSashPosition();
if ( new_sash_position == -1 )
{
// change not allowed
return;
}
// change not allowed
return;
}
if (new_sash_position == m_sashPosition)
if ( posSashNew == m_sashPosition )
return;
// Erase old tracker
@@ -338,9 +319,9 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
}
if (m_splitMode == wxSPLIT_VERTICAL)
x = new_sash_position;
x = posSashNew;
else
y = new_sash_position;
y = posSashNew;
// Remember old positions
m_oldX = x;
@@ -366,18 +347,13 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
}
else
{
DoSetSashPosition(new_sash_position);
DoSetSashPosition(posSashNew);
m_needUpdating = TRUE;
}
}
else if ( event.LeftDClick() )
{
wxSplitterEvent eventSplitter(wxEVT_COMMAND_SPLITTER_DOUBLECLICKED,
this);
eventSplitter.m_data.pt.x = x;
eventSplitter.m_data.pt.y = y;
(void)GetEventHandler()->ProcessEvent(eventSplitter);
OnDoubleClickSash(x, y);
}
}
@@ -743,7 +719,12 @@ int wxSplitterWindow::AdjustSashPosition(int sashPos) const
void wxSplitterWindow::DoSetSashPosition(int 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.
@@ -865,7 +846,7 @@ bool wxSplitterWindow::Unsplit(wxWindow *toRemove)
return FALSE;
}
SendUnsplitEvent(win);
OnUnsplit(win);
DoSetSashPosition(0);
SizeWindows();
@@ -951,31 +932,38 @@ void wxSplitterWindow::InitColours()
#endif // __WIN16__
}
void wxSplitterWindow::SendUnsplitEvent(wxWindow *winRemoved)
bool wxSplitterWindow::DoSendEvent(wxSplitterEvent& event)
{
wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_UNSPLIT, this);
event.m_data.win = winRemoved;
(void)GetEventHandler()->ProcessEvent(event);
return !GetEventHandler()->ProcessEvent(event) || event.IsAllowed();
}
// ---------------------------------------------------------------------------
// 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.
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
int window_size = GetWindowSize();
bool unsplit_scenario = FALSE;
if ( m_permitUnsplitAlways
|| m_minimumPaneSize == 0 )
if ( m_permitUnsplitAlways || m_minimumPaneSize == 0 )
{
// Do edge detection if unsplit premitted
if ( newSashPosition <= UNSPLIT_THRESHOLD )
@@ -1003,50 +991,61 @@ void wxSplitterWindow::OnSashPosChanged(wxSplitterEvent& event)
if ( newSashPosition < 0 || newSashPosition > window_size )
newSashPosition = window_size / 2;
// for compatibility, call the virtual function
if ( !OnSashPositionChange(newSashPosition) )
// now let the event handler have it
//
// 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;
}
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
// the sash if the minimum pane size is zero.
void wxSplitterWindow::OnDoubleClick(wxSplitterEvent& event)
void wxSplitterWindow::OnDoubleClickSash(int x, int y)
{
// for compatibility, call the virtual function
OnDoubleClickSash(event.GetX(), event.GetY());
if ( GetMinimumPaneSize() == 0 || m_permitUnsplitAlways )
// 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) )
{
Unsplit();
if ( GetMinimumPaneSize() == 0 || m_permitUnsplitAlways )
{
Unsplit();
}
}
//else: blocked by user
}
void wxSplitterWindow::OnUnsplitEvent(wxSplitterEvent& event)
void wxSplitterWindow::OnUnsplit(wxWindow *winRemoved)
{
wxWindow *win = event.GetWindowBeingRemoved();
// do it before calling the event handler which may delete the window
winRemoved->Show(FALSE);
// do it before calling OnUnsplit() which may delete the window
win->Show(FALSE);
wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_UNSPLIT, this);
event.m_data.win = winRemoved;
// for compatibility, call the virtual function
OnUnsplit(win);
(void)DoSendEvent(event);
}
#if defined(__WXMSW__)
#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...
#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:
// and like this we explicitly say that our cursor should not be used for
// children windows which overlap us
@@ -1057,5 +1056,7 @@ void wxSplitterWindow::OnSetCursor(wxSetCursorEvent& WXUNUSED_UNLESS_MSW(event))
event.Skip();
}
//else: do nothing, in particular, don't call Skip()
#endif // wxMSW
}
#endif // wxMSW