X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3e58dcb9058f177d767c6f39baa88ee5626266a9..275a63e3a6dc26c411c39a557be003bc4f2aaaaa:/src/generic/splitter.cpp diff --git a/src/generic/splitter.cpp b/src/generic/splitter.cpp index 0ee00d2fd3..1e51050540 100644 --- a/src/generic/splitter.cpp +++ b/src/generic/splitter.cpp @@ -1,12 +1,12 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: splitter.cpp +// Name: src/generic/splitter.cpp // Purpose: wxSplitterWindow implementation // Author: Julian Smart // Modified by: // Created: 01/02/97 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Copyright: (c) Julian Smart +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ @@ -21,19 +21,22 @@ #endif #ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/log.h" + + #include "wx/dcscreen.h" + #include "wx/window.h" #include "wx/dialog.h" #include "wx/frame.h" -#endif -#include + #include "wx/settings.h" +#endif -#include "wx/string.h" #include "wx/splitter.h" -#include "wx/dcscreen.h" -#include "wx/settings.h" -#include "wx/log.h" -#include "wx/utils.h" + +#include DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED) DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING) @@ -49,7 +52,7 @@ BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow) EVT_IDLE(wxSplitterWindow::OnIdle) EVT_MOUSE_EVENTS(wxSplitterWindow::OnMouseEvent) -#ifdef __WXMSW__ +#if defined( __WXMSW__ ) || defined( __WXMAC__) EVT_SET_CURSOR(wxSplitterWindow::OnSetCursor) #endif // wxMSW @@ -107,12 +110,12 @@ void wxSplitterWindow::Init() m_oldY = 0; m_firstX = 0; m_firstY = 0; - m_sashSize = 7; - m_borderSize = 2; + m_sashSize = 3; + m_borderSize = 0; m_sashPosition = m_requestedSashPosition = 0; m_minimumPaneSize = 0; - m_sashCursorWE = new wxCursor(wxCURSOR_SIZEWE); - m_sashCursorNS = new wxCursor(wxCURSOR_SIZENS); + m_sashCursorWE = wxCursor(wxCURSOR_SIZEWE); + m_sashCursorNS = wxCursor(wxCURSOR_SIZENS); m_sashTrackerPen = new wxPen(*wxBLACK, 2, wxSOLID); m_lightShadowPen = (wxPen *) NULL; m_mediumShadowPen = (wxPen *) NULL; @@ -121,9 +124,6 @@ void wxSplitterWindow::Init() m_facePen = (wxPen *) NULL; m_hilightPen = (wxPen *) NULL; - m_borderSize = 0; - m_sashSize = 3; - InitColours(); m_needUpdating = FALSE; @@ -131,8 +131,6 @@ void wxSplitterWindow::Init() wxSplitterWindow::~wxSplitterWindow() { - delete m_sashCursorWE; - delete m_sashCursorNS; delete m_sashTrackerPen; delete m_lightShadowPen; delete m_darkShadowPen; @@ -142,6 +140,12 @@ wxSplitterWindow::~wxSplitterWindow() delete m_faceBrush; } +void wxSplitterWindow::SetResizeCursor() +{ + SetCursor(m_splitMode == wxSPLIT_VERTICAL ? m_sashCursorWE + : m_sashCursorNS); +} + void wxSplitterWindow::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); @@ -164,41 +168,43 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) int x = (int)event.GetX(), y = (int)event.GetY(); - // reset the cursor -#ifdef __WXMOTIF__ - SetCursor(* wxSTANDARD_CURSOR); -#endif -#ifdef __WXMSW__ - SetCursor(wxCursor()); +#if defined(__WXMSW__) + // SetCursor(wxCursor()); // Is this required? #endif if (GetWindowStyle() & wxSP_NOSASH) return; + // with wxSP_LIVE_UPDATE style the splitter windows are always resized + // following the mouse movement while it drags the sash, without it we only + // draw the sash at the new position but only resize the windows when the + // dragging is finished + bool isLive = (GetWindowStyleFlag() & wxSP_LIVE_UPDATE) != 0; + if (event.LeftDown()) { if ( SashHitTest(x, y) ) { - CaptureMouse(); - + // Start the drag now m_dragMode = wxSPLIT_DRAG_DRAGGING; + + // Capture mouse and set the cursor + CaptureMouse(); + SetResizeCursor(); - if ((GetWindowStyleFlag() & wxSP_LIVE_UPDATE) == 0) + if ( !isLive ) { + // remember the initial sash position and draw the initial + // shadow sash + m_sashPositionCurrent = m_sashPosition; + DrawSashTracker(x, y); } m_oldX = x; m_oldY = y; - if ( m_splitMode == wxSPLIT_VERTICAL ) - { - SetCursor(*m_sashCursorWE); - } - else - { - SetCursor(*m_sashCursorNS); - } + SetResizeCursor(); return; } } @@ -206,10 +212,19 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) { // We can stop dragging now and see what we've got. m_dragMode = wxSPLIT_DRAG_NONE; + + // Release mouse and unset the cursor ReleaseMouse(); + SetCursor(* wxSTANDARD_CURSOR); + + // exit if unsplit after doubleclick + if ( !IsSplit() ) + { + return; + } // Erase old tracker - if ((GetWindowStyleFlag() & wxSP_LIVE_UPDATE) == 0) + if ( !isLive ) { DrawSashTracker(m_oldX, m_oldY); } @@ -219,7 +234,8 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) // mouse has moved int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY; - int posSashNew = OnSashPositionChanging(m_sashPosition + diff); + int posSashOld = isLive ? m_sashPosition : m_sashPositionCurrent; + int posSashNew = OnSashPositionChanging(posSashOld + diff); if ( posSashNew == -1 ) { // change not allowed @@ -236,7 +252,7 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) m_windowOne = m_windowTwo; m_windowTwo = (wxWindow *) NULL; OnUnsplit(removedWindow); - DoSetSashPosition(0); + SetSashPositionAndNotify(0); } else if ( posSashNew == GetWindowSize() ) { @@ -244,65 +260,39 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) wxWindow *removedWindow = m_windowTwo; m_windowTwo = (wxWindow *) NULL; OnUnsplit(removedWindow); - DoSetSashPosition(0); + SetSashPositionAndNotify(0); } else { - DoSetSashPosition(posSashNew); + SetSashPositionAndNotify(posSashNew); } } else { - DoSetSashPosition(posSashNew); + SetSashPositionAndNotify(posSashNew); } SizeWindows(); } // left up && dragging else if (event.Moving() && !event.Dragging()) { - // Just change the cursor if required + // Just change the cursor as required if ( SashHitTest(x, y) ) - { - if ( m_splitMode == wxSPLIT_VERTICAL ) - { - SetCursor(*m_sashCursorWE); - } - else - { - SetCursor(*m_sashCursorNS); - } - } -#if defined(__WXGTK__) || defined(__WXMSW__) + SetResizeCursor(); else - { - // We must set the normal cursor in MSW, because - // if the child window doesn't have a cursor, the - // parent's (splitter window) will be used, and this - // must be the standard cursor. - - // where else do we unset the cursor? SetCursor(* wxSTANDARD_CURSOR); - } -#endif // __WXGTK__ } else if (event.Dragging() && (m_dragMode == wxSPLIT_DRAG_DRAGGING)) { -#ifdef __WXMSW__ - // Otherwise, the cursor sometimes reverts to the normal cursor - // during dragging. - if ( m_splitMode == wxSPLIT_VERTICAL ) - { - SetCursor(*m_sashCursorWE); - } - else + int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY; + if ( !diff ) { - SetCursor(*m_sashCursorNS); + // nothing to do, mouse didn't really move far enough + return; } -#endif // __WXMSW__ - - int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY; - int posSashNew = OnSashPositionChanging(m_sashPosition + diff); + int posSashOld = isLive ? m_sashPosition : m_sashPositionCurrent; + int posSashNew = OnSashPositionChanging(posSashOld + diff); if ( posSashNew == -1 ) { // change not allowed @@ -313,7 +303,7 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) return; // Erase old tracker - if ((GetWindowStyleFlag() & wxSP_LIVE_UPDATE) == 0) + if ( !isLive ) { DrawSashTracker(m_oldX, m_oldY); } @@ -341,17 +331,19 @@ void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) #endif // __WXMSW__ // Draw new one - if ((GetWindowStyleFlag() & wxSP_LIVE_UPDATE) == 0) + if ( !isLive ) { + m_sashPositionCurrent = posSashNew; + DrawSashTracker(m_oldX, m_oldY); } else { - DoSetSashPosition(posSashNew); + SetSashPositionAndNotify(posSashNew); m_needUpdating = TRUE; } } - else if ( event.LeftDClick() ) + else if ( event.LeftDClick() && m_windowTwo ) { OnDoubleClickSash(x, y); } @@ -388,7 +380,7 @@ void wxSplitterWindow::OnSize(wxSizeEvent& event) iconized = FALSE; } #endif - + if ( iconized ) { event.Skip(); @@ -403,12 +395,12 @@ void wxSplitterWindow::OnSize(wxSizeEvent& event) if ( m_splitMode == wxSPLIT_VERTICAL ) { if ( m_sashPosition >= (cw - 5) ) - DoSetSashPosition(wxMax(10, cw - 40)); + SetSashPositionAndNotify(wxMax(10, cw - 40)); } else // m_splitMode == wxSPLIT_HORIZONTAL { if ( m_sashPosition >= (ch - 5) ) - DoSetSashPosition(wxMax(10, ch - 40)); + SetSashPositionAndNotify(wxMax(10, ch - 40)); } } @@ -536,7 +528,7 @@ void wxSplitterWindow::DrawSash(wxDC& dc) dc.DrawLine(m_sashPosition+1, h-m_borderSize-1, m_sashPosition+m_sashSize-1, h-m_borderSize-1); } } - else + else // wxSPLIT_HORIZONTAL { dc.SetPen(*m_facePen); if (HasFlag( wxSP_SASH_AQUA )) @@ -576,12 +568,12 @@ void wxSplitterWindow::DrawSash(wxDC& dc) } } } - else + else // !wxSP_3DSASH { + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(*m_faceBrush); if ( m_splitMode == wxSPLIT_VERTICAL ) { - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxBLACK_BRUSH); int h1 = h-1; int y1 = 0; if ( (GetWindowStyleFlag() & wxSP_BORDER) != wxSP_BORDER && (GetWindowStyleFlag() & wxSP_3DBORDER) != wxSP_3DBORDER ) @@ -592,10 +584,8 @@ void wxSplitterWindow::DrawSash(wxDC& dc) } dc.DrawRectangle(m_sashPosition, y1, m_sashSize, h1); } - else + else // wxSPLIT_HORIZONTAL { - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxBLACK_BRUSH); int w1 = w-1; int x1 = 0; if ( (GetWindowStyleFlag() & wxSP_BORDER) != wxSP_BORDER && (GetWindowStyleFlag() & wxSP_3DBORDER) != wxSP_3DBORDER ) @@ -606,7 +596,6 @@ void wxSplitterWindow::DrawSash(wxDC& dc) } dc.DrawRectangle(x1, m_sashPosition, w1, m_sashSize); } - } dc.SetPen(wxNullPen); @@ -716,15 +705,27 @@ int wxSplitterWindow::AdjustSashPosition(int sashPos) const return sashPos; } -void wxSplitterWindow::DoSetSashPosition(int sashPos) +bool wxSplitterWindow::DoSetSashPosition(int sashPos) { - m_requestedSashPosition = sashPos; - m_sashPosition = sashPos == 0 ? 0 : AdjustSashPosition(sashPos); + int newSashPosition = AdjustSashPosition(sashPos); - wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, this); - event.m_data.pos = m_sashPosition; + if ( newSashPosition == m_sashPosition ) + return FALSE; - (void)DoSendEvent(event); + m_sashPosition = newSashPosition; + + return TRUE; +} + +void wxSplitterWindow::SetSashPositionAndNotify(int sashPos) +{ + if ( DoSetSashPosition(sashPos) ) + { + wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, this); + event.m_data.pos = m_sashPosition; + + (void)DoSendEvent(event); + } } // Position and size subwindows. @@ -732,15 +733,29 @@ void wxSplitterWindow::DoSetSashPosition(int sashPos) // including the edges next to the sash. void wxSplitterWindow::SizeWindows() { - if ( m_requestedSashPosition != m_sashPosition ) - DoSetSashPosition(m_requestedSashPosition); + // check if we have delayed setting the real sash position + if ( m_requestedSashPosition != INT_MAX ) + { + int newSashPosition = ConvertSashPosition(m_requestedSashPosition); + if ( newSashPosition != m_sashPosition ) + { + DoSetSashPosition(newSashPosition); + } + + if ( newSashPosition <= m_sashPosition + && newSashPosition >= m_sashPosition - GetBorderSize() ) + { + // don't update it any more + m_requestedSashPosition = INT_MAX; + } + } int w, h; GetClientSize(&w, &h); if ( GetWindow1() && !GetWindow2() ) { - GetWindow1()->SetSize(GetBorderSize(), GetBorderSize(), + GetWindow1()->SetSize(GetBorderSize(), GetBorderSize(), w - 2*GetBorderSize(), h - 2*GetBorderSize()); } else if ( GetWindow1() && GetWindow2() ) @@ -779,6 +794,9 @@ void wxSplitterWindow::SizeWindows() // Set pane for unsplit window void wxSplitterWindow::Initialize(wxWindow *window) { + wxASSERT_MSG( window && window->GetParent() == this, + _T("windows in the splitter should have it as parent!") ); + m_windowOne = window; m_windowTwo = (wxWindow *) NULL; DoSetSashPosition(0); @@ -794,30 +812,43 @@ bool wxSplitterWindow::DoSplit(wxSplitMode mode, if ( IsSplit() ) return FALSE; - int window_size = GetWindowSize(); + wxCHECK_MSG( window1 && window2, FALSE, + _T("can not split with NULL window(s)") ); + + wxCHECK_MSG( window1->GetParent() == this && window2->GetParent() == this, FALSE, + _T("windows in the splitter should have it as parent!") ); m_splitMode = mode; m_windowOne = window1; m_windowTwo = window2; + // remember the sash position we want to set for later if we can't set it + // right now (e.g. because the window is too small) + m_requestedSashPosition = sashPosition; + + DoSetSashPosition(ConvertSashPosition(sashPosition)); + + SizeWindows(); + + return TRUE; +} + +int wxSplitterWindow::ConvertSashPosition(int sashPosition) const +{ if ( sashPosition > 0 ) { - DoSetSashPosition(sashPosition); + return sashPosition; } else if ( sashPosition < 0 ) { // It's negative so adding is subtracting - DoSetSashPosition(window_size + sashPosition); + return GetWindowSize() + sashPosition; } - else + else // sashPosition == 0 { - // default - DoSetSashPosition(window_size/2); + // default, put it in the centre + return GetWindowSize() / 2; } - - SizeWindows(); - - return TRUE; } // Remove the specified (or second) window from the view @@ -846,7 +877,7 @@ bool wxSplitterWindow::Unsplit(wxWindow *toRemove) return FALSE; } - OnUnsplit(win); + win->Show(FALSE); DoSetSashPosition(0); SizeWindows(); @@ -1016,6 +1047,8 @@ int wxSplitterWindow::OnSashPositionChanging(int newSashPosition) // the sash if the minimum pane size is zero. void wxSplitterWindow::OnDoubleClickSash(int x, int y) { + wxCHECK_RET(m_windowTwo, wxT("splitter: no window to remove")); + // new code should handle events instead of using the virtual functions wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, this); event.m_data.pt.x = x; @@ -1024,7 +1057,9 @@ void wxSplitterWindow::OnDoubleClickSash(int x, int y) { if ( GetMinimumPaneSize() == 0 || m_permitUnsplitAlways ) { - Unsplit(); + wxWindow* win = m_windowTwo; + if (Unsplit(win)) + OnUnsplit(win); } } //else: blocked by user @@ -1041,7 +1076,7 @@ void wxSplitterWindow::OnUnsplit(wxWindow *winRemoved) (void)DoSendEvent(event); } -#ifdef __WXMSW__ +#if defined( __WXMSW__ ) || defined( __WXMAC__) // this is currently called (and needed) under MSW only... void wxSplitterWindow::OnSetCursor(wxSetCursorEvent& event)