]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/splitter.cpp
* prgodlgg.h: Update() use wxString instead of 'char *'
[wxWidgets.git] / src / generic / splitter.cpp
index 7f631aa457f8631090dee6ecbf10299c45f3e2ed..0d926085d458a2f5f4d73d880c8641a14b45c4f6 100644 (file)
@@ -6,23 +6,22 @@
 // Created:     01/02/97
 // RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart and Markus Holzem
-// Licence:       wxWindows license
+// Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
 #ifdef __GNUG__
-#pragma implementation "splitter.h"
-// #pragma interface
+    #pragma implementation "splitter.h"
 #endif
 
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-#pragma hdrstop
+    #pragma hdrstop
 #endif
 
 #ifndef WX_PRECOMP
-#include "wx/wx.h"
+    #include "wx/wx.h"
 #endif
 
 #include <math.h>
@@ -141,10 +140,29 @@ void wxSplitterWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
     DrawSash(dc);
 }
 
+
 void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
 {
-    long x, y;
-    event.Position(&x, &y);
+    long x = event.GetX();
+    long y = event.GetY();
+
+    // reset the cursor
+#ifdef __WXMOTIF__
+    SetCursor(* wxSTANDARD_CURSOR);
+#endif
+#ifdef __WXMSW__
+    SetCursor(wxCursor());
+#endif
+
+    // under wxGTK the method above causes the mouse
+    // to flicker so we set the standard cursor only
+    // when leaving the window and when moving over
+    // non-sash parts of the window. this should work
+    // on the other platforms as well, but who knows.
+#ifdef __WXGTK__
+    if (event.Leaving())
+        SetCursor(* wxSTANDARD_CURSOR);
+#endif
 
     if (event.LeftDown())
     {
@@ -152,101 +170,57 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
         {
             CaptureMouse();
 
-            // Required for X to specify that
-            // that we wish to draw on top of all windows
-            // - and we optimise by specifying the area
-            // for creating the overlap window.
-            wxScreenDC::StartDrawingOnTop(this);
-
-            // We don't say we're dragging yet; we leave that
-            // decision for the Dragging() branch, to ensure
-            // the user has dragged a little bit.
-            m_dragMode = wxSPLIT_DRAG_LEFT_DOWN;
-            m_firstX = x;
-            m_firstY = y;
-        }
-    }
-    else if ( event.LeftUp() && m_dragMode == wxSPLIT_DRAG_LEFT_DOWN )
-    {
-        // Wasn't a proper drag
-        ReleaseMouse();
-        wxScreenDC::EndDrawingOnTop();
-        m_dragMode = wxSPLIT_DRAG_NONE;
+            m_dragMode = wxSPLIT_DRAG_DRAGGING;
 
-        SetCursor(*wxSTANDARD_CURSOR);
+            DrawSashTracker(x, y);
+            m_oldX = x;
+            m_oldY = y;
+            return;
+        }
     }
     else if (event.LeftUp() && m_dragMode == wxSPLIT_DRAG_DRAGGING)
     {
         // We can stop dragging now and see what we've got.
         m_dragMode = wxSPLIT_DRAG_NONE;
         ReleaseMouse();
+
         // Erase old tracker
         DrawSashTracker(m_oldX, m_oldY);
 
-        // End drawing on top (frees the window used for drawing
-        // over the screen)
-        wxScreenDC::EndDrawingOnTop();
-
+        // Obtain window size. We are only interested in the dimension the sash
+        // splits up
         int w, h;
         GetClientSize(&w, &h);
-        if ( m_splitMode == wxSPLIT_VERTICAL )
+        int window_size = (m_splitMode == wxSPLIT_VERTICAL ? w : h );
+        int new_sash_position =
+            (int) ( m_splitMode == wxSPLIT_VERTICAL ? x : y );
+
+        if ( !OnSashPositionChange(new_sash_position) )
+            return;
+
+        if ( new_sash_position == 0 )
         {
-            if ( !OnSashPositionChange(x) )
-                return;
-
-            if ( x <= 4 )
-            {
-                // We remove the first window from the view
-                wxWindow *removedWindow = m_windowOne;
-                m_windowOne = m_windowTwo;
-                m_windowTwo = (wxWindow *) NULL;
-
-                OnUnsplit(removedWindow);
-                m_sashPosition = 0;
-            }
-            else if ( x >= (w - 4) )
-            {
-                // We remove the second window from the view
-                wxWindow *removedWindow = m_windowTwo;
-                m_windowTwo = (wxWindow *) NULL;
-                OnUnsplit(removedWindow);
-                m_sashPosition = 0;
-            }
-            else
-            {
-                m_sashPosition = x;
-            }
+            // We remove the first window from the view
+            wxWindow *removedWindow = m_windowOne;
+            m_windowOne = m_windowTwo;
+            m_windowTwo = (wxWindow *) NULL;
+            OnUnsplit(removedWindow);
+            m_sashPosition = 0;
+        }
+        else if ( new_sash_position == window_size )
+        {
+            // We remove the second window from the view
+            wxWindow *removedWindow = m_windowTwo;
+            m_windowTwo = (wxWindow *) NULL;
+            OnUnsplit(removedWindow);
+            m_sashPosition = 0;
         }
         else
         {
-            if ( !OnSashPositionChange(y) )
-                return;
-
-            if ( y <= 4 )
-            {
-                // We remove the first window from the view
-                wxWindow *removedWindow = m_windowOne;
-                m_windowOne = m_windowTwo;
-                m_windowTwo = (wxWindow *) NULL;
-
-                OnUnsplit(removedWindow);
-                m_sashPosition = 0;
-            }
-            else if ( y >= (h - 4) )
-            {
-                // We remove the second window from the view
-                wxWindow *removedWindow = m_windowTwo;
-                m_windowTwo = (wxWindow *) NULL;
-                OnUnsplit(removedWindow);
-                m_sashPosition = 0;
-            }
-            else
-            {
-                m_sashPosition = y;
-            }
+            m_sashPosition = new_sash_position;
         }
         SizeWindows();
-    }
+    }  // left up && dragging
     else if (event.Moving() && !event.Dragging())
     {
         // Just change the cursor if required
@@ -261,42 +235,22 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
                     SetCursor(*m_sashCursorNS);
                 }
         }
+#ifdef __WXGTK__
         else
-        {
-            SetCursor(*wxSTANDARD_CURSOR);
-        }
+       {
+           // where else do we unset the cursor?
+            SetCursor(* wxSTANDARD_CURSOR);
+       }
+#endif
     }
-    else if ( (event.Dragging() && (m_dragMode == wxSPLIT_DRAG_DRAGGING)) ||
-              (event.Dragging() && SashHitTest(x, y, 4)) )
+    else if (event.Dragging() && (m_dragMode == wxSPLIT_DRAG_DRAGGING)) 
     {
-         if ( m_splitMode == wxSPLIT_VERTICAL )
-         {
-            SetCursor(*m_sashCursorWE);
-         }
-         else
-         {
-            SetCursor(*m_sashCursorNS);
-         }
-
-        // Detect that this is really a drag: we've moved more than 1 pixel either way
-        if ((m_dragMode == wxSPLIT_DRAG_LEFT_DOWN) &&
-//                (abs((int)x - m_firstX) > 1 || abs((int)y - m_firstY) > 1) )
-                (abs((int)x - m_firstX) > 0 || abs((int)y - m_firstY) > 1) )
-        {
-            m_dragMode = wxSPLIT_DRAG_DRAGGING;
-            DrawSashTracker(x, y);
-        }
-        else
-        {
-          if ( m_dragMode == wxSPLIT_DRAG_DRAGGING )
-          {
-            // Erase old tracker
-            DrawSashTracker(m_oldX, m_oldY);
+        // Erase old tracker
+        DrawSashTracker(m_oldX, m_oldY);
+
+        // Draw new one
+        DrawSashTracker(x, y);
 
-            // Draw new one
-            DrawSashTracker(x, y);
-          }
-        }
         m_oldX = x;
         m_oldY = y;
     }
@@ -304,9 +258,6 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event)
     {
         OnDoubleClickSash(x, y);
     }
-    else
-    {
-    }
 }
 
 void wxSplitterWindow::OnSize(wxSizeEvent& WXUNUSED(event))
@@ -631,25 +582,54 @@ bool wxSplitterWindow::Unsplit(wxWindow *toRemove)
     if ( ! IsSplit() )
         return FALSE;
 
+    wxWindow *win = NULL;
     if ( toRemove == NULL || toRemove == m_windowTwo)
     {
-        wxWindow *win = m_windowTwo ;
+        win = m_windowTwo ;
         m_windowTwo = (wxWindow *) NULL;
-        m_sashPosition = 0;
-        OnUnsplit(win);
-        SizeWindows();
     }
     else if ( toRemove == m_windowOne )
     {
-        wxWindow *win = m_windowOne ;
+        win = m_windowOne ;
         m_windowOne = m_windowTwo;
         m_windowTwo = (wxWindow *) NULL;
-        m_sashPosition = 0;
-        OnUnsplit(win);
-        SizeWindows();
     }
     else
+    {
+        wxFAIL_MSG(_T("splitter: attempt to remove a non-existent window"));
+
         return FALSE;
+    }
+
+    OnUnsplit(win);
+    m_sashPosition = 0;
+    SizeWindows();
+
+    return TRUE;
+}
+
+// Replace a window with another one
+bool wxSplitterWindow::ReplaceWindow(wxWindow *winOld, wxWindow *winNew)
+{
+    wxCHECK_MSG( winOld, FALSE, _T("use one of Split() functions instead") );
+    wxCHECK_MSG( winNew, FALSE, _T("use Unsplit() functions instead") );
+
+    if ( winOld == m_windowTwo )
+    {
+        m_windowTwo = winNew;
+    }
+    else if ( winOld == m_windowOne )
+    {
+        m_windowOne = winNew;
+    }
+    else
+    {
+        wxFAIL_MSG(_T("splitter: attempt to replace a non-existent window"));
+
+        return FALSE;
+    }
+
+    SizeWindows();
 
     return TRUE;
 }
@@ -664,29 +644,43 @@ void wxSplitterWindow::SetSashPosition(int position, bool redraw)
     }
 }
 
-bool wxSplitterWindow::OnSashPositionChange(int newSashPosition)
+bool wxSplitterWindow::OnSashPositionChange(int& newSashPosition)
 {
-  // is the left/upper pane too small?
-  if ( newSashPosition < m_minimumPaneSize )
-    return NULL;
-
-  // is the right/lower pane too small?
-  int w, h;
-  GetClientSize(&w, &h);
-
-  if ( m_splitMode == wxSPLIT_VERTICAL )
-  {
-    if ( h - newSashPosition < m_minimumPaneSize )
-      return FALSE;
-  }
-  else // m_splitMode = wxSPLIT_HORIZONTAL
-  {
-    if ( w - newSashPosition < m_minimumPaneSize )
-      return FALSE;
-  }
-
-  // it's ok to move sash
-  return TRUE;
+    // If within UNSPLIT_THRESHOLD from edge, set to edge to cause closure.
+    const int UNSPLIT_THRESHOLD = 4;
+
+    if (newSashPosition <= UNSPLIT_THRESHOLD)   // threshold top / left check
+    {
+        newSashPosition = 0;
+        return TRUE;
+    }
+
+    // Obtain relevant window dimension for bottom / right threshold check
+    int w, h;
+    GetClientSize(&w, &h);
+    int window_size = (m_splitMode == wxSPLIT_VERTICAL) ? w : h ;
+
+    if ( newSashPosition >= window_size - UNSPLIT_THRESHOLD )
+    {
+        newSashPosition = window_size;
+        return TRUE;
+    }
+
+    // If resultant pane would be too small, enlarge it.
+
+    // Check upper / left pane
+    if ( newSashPosition < m_minimumPaneSize )
+        newSashPosition = m_minimumPaneSize;   // NB: don't return just yet
+
+    // Check lower / right pane (check even if sash was just adjusted)
+    if ( newSashPosition > window_size - m_minimumPaneSize )
+        newSashPosition = window_size - m_minimumPaneSize;
+
+    // If the result is out of bounds it means minimum size is too big, so
+    // split window in half as best compromise.
+    if (newSashPosition < 0 || newSashPosition > window_size)
+        newSashPosition = window_size / 2;
+    return TRUE;
 }
 
 // Called when the sash is double-clicked.