From 3e58dcb9058f177d767c6f39baa88ee5626266a9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 16 Feb 2002 21:53:52 +0000 Subject: [PATCH] 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 --- docs/latex/wx/splitevt.tex | 18 ++-- include/wx/generic/splitter.h | 32 +++--- src/generic/splitter.cpp | 179 +++++++++++++++++----------------- 3 files changed, 120 insertions(+), 109 deletions(-) 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 + -- 2.45.2