]> git.saurik.com Git - wxWidgets.git/commitdiff
various splitter fixes:
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 16 Feb 2002 21:53:52 +0000 (21:53 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 16 Feb 2002 21:53:52 +0000 (21:53 +0000)
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
include/wx/generic/splitter.h
src/generic/splitter.cpp

index ffaff7fcf20f6543dcefc0537613ad8f9bc07ccf..1b57bba02db0c8e5d0254df91f3249f0d401d769 100644 (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}
index ca6f119c2b8a08a39547dc8cc274f00286204098..fabcbfcf8af0de8d54c326c86e0dbd191f4c6d84 100644 (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();
index 1d29a0b782c741db3e6660a10d84dee60b85af19..0ee00d2fd304fb080abca63cc152fc17e17af513 100644 (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
+