diff --git a/docs/latex/wx/splitevt.tex b/docs/latex/wx/splitevt.tex index ffaff7fcf2..1b57bba02d 100644 --- a/docs/latex/wx/splitevt.tex +++ b/docs/latex/wx/splitevt.tex @@ -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} diff --git a/include/wx/generic/splitter.h b/include/wx/generic/splitter.h index ca6f119c2b..fabcbfcf8a 100644 --- a/include/wx/generic/splitter.h +++ b/include/wx/generic/splitter.h @@ -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(); diff --git a/src/generic/splitter.cpp b/src/generic/splitter.cpp index 1d29a0b782..0ee00d2fd3 100644 --- a/src/generic/splitter.cpp +++ b/src/generic/splitter.cpp @@ -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 +