X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/12a3f2275c94a345cf83abf5151db68391859623..4b2322641a8c15b849c7221438ad9f1a7366afa6:/src/gtk/scrolwin.cpp diff --git a/src/gtk/scrolwin.cpp b/src/gtk/scrolwin.cpp index ff1c2da0a0..80ba00f515 100644 --- a/src/gtk/scrolwin.cpp +++ b/src/gtk/scrolwin.cpp @@ -1,12 +1,12 @@ ///////////////////////////////////////////////////////////////////////////// // Name: gtk/scrolwin.cpp // Purpose: wxScrolledWindow implementation -// Author: Julian Smart +// Author: Robert Roebling // Modified by: Ron Lee // Created: 01/02/97 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -17,10 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "scrolwin.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -28,12 +24,12 @@ #pragma hdrstop #endif +#include "wx/scrolwin.h" #include "wx/utils.h" #include "wx/dcclient.h" - -#include "wx/scrolwin.h" #include "wx/panel.h" #include "wx/sizer.h" +#include "wx/math.h" #include "wx/gtk/private.h" #include "wx/gtk/win_gtk.h" @@ -73,6 +69,7 @@ extern bool g_isIdle; // "value_changed" from m_vAdjust //----------------------------------------------------------------------------- +extern "C" { static void gtk_scrolled_window_vscroll_callback( GtkAdjustment *adjust, SCROLLBAR_CBACK_ARG wxScrolledWindow *win ) @@ -87,11 +84,13 @@ static void gtk_scrolled_window_vscroll_callback( GtkAdjustment *adjust, win->GtkVScroll( adjust->value, GET_SCROLL_TYPE(GTK_SCROLLED_WINDOW(win->m_widget)->vscrollbar) ); } +} //----------------------------------------------------------------------------- // "value_changed" from m_hAdjust //----------------------------------------------------------------------------- +extern "C" { static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust, SCROLLBAR_CBACK_ARG wxScrolledWindow *win ) @@ -105,11 +104,13 @@ static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust, win->GtkHScroll( adjust->value, GET_SCROLL_TYPE(GTK_SCROLLED_WINDOW(win->m_widget)->hscrollbar) ); } +} //----------------------------------------------------------------------------- // "button_press_event" from scrollbar //----------------------------------------------------------------------------- +extern "C" { static gint gtk_scrollbar_button_press_callback( GtkRange *widget, GdkEventButton *gdk_event, wxWindowGTK *win) @@ -126,11 +127,13 @@ static gint gtk_scrollbar_button_press_callback( GtkRange *widget, return FALSE; } +} //----------------------------------------------------------------------------- // "button_release_event" from scrollbar //----------------------------------------------------------------------------- +extern "C" { static gint gtk_scrollbar_button_release_callback( GtkRange *widget, GdkEventButton *WXUNUSED(gdk_event), wxWindowGTK *win) @@ -169,6 +172,7 @@ static gint gtk_scrollbar_button_release_callback( GtkRange *widget, return FALSE; } +} //----------------------------------------------------------------------------- // InsertChild for wxScrolledWindow @@ -288,7 +292,7 @@ bool wxScrolledWindow::Create(wxWindow *parent, GtkHConnectEvent(); // these handlers block mouse events to any window during scrolling such as - // motion events and prevent GTK and wxWindows from fighting over where the + // motion events and prevent GTK and wxWidgets from fighting over where the // slider should be gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event", @@ -313,7 +317,7 @@ bool wxScrolledWindow::Create(wxWindow *parent, PostCreation(); Show( TRUE ); - + return TRUE; } @@ -326,10 +330,62 @@ void wxScrolledWindow::DoSetVirtualSize( int x, int y ) wxPanel::DoSetVirtualSize( x, y ); AdjustScrollbars(); -#if wxUSE_CONSTRAINTS if (GetAutoLayout()) Layout(); -#endif +} + +// wxWindow's GetBestVirtualSize returns the actual window size, +// whereas we want to return the virtual size +wxSize wxScrolledWindow::GetBestVirtualSize() const +{ + wxSize clientSize( GetClientSize() ); + if (GetSizer()) + { + wxSize minSize( GetSizer()->CalcMin() ); + + return wxSize( wxMax( clientSize.x, minSize.x ), wxMax( clientSize.y, minSize.y ) ); + } + else + return clientSize; +} + +// return the size best suited for the current window +// (this isn't a virtual size, this is a sensible size for the window) +wxSize wxScrolledWindow::DoGetBestSize() const +{ + wxSize best; + + if ( GetSizer() ) + { + wxSize b = GetSizer()->GetMinSize(); + + // Only use the content to set the window size in the direction + // where there's no scrolling; otherwise we're going to get a huge + // window in the direction in which scrolling is enabled + int ppuX, ppuY; + GetScrollPixelsPerUnit(& ppuX, & ppuY); + + wxSize minSize; + if ( GetMinSize().IsFullySpecified() ) + minSize = GetMinSize(); + else + minSize = GetSize(); + + if (ppuX > 0) + b.x = minSize.x; + if (ppuY > 0) + b.y = minSize.y; + best = b; + } + else + return wxWindow::DoGetBestSize(); + + // Add any difference between size and client size + wxSize diff = GetSize() - GetClientSize(); + best.x += wxMax(0, diff.x); + best.y += wxMax(0, diff.y); + + return best; } /* @@ -340,8 +396,11 @@ void wxScrolledWindow::SetScrollbars( int pixelsPerUnitX, int pixelsPerUnitY, int noUnitsX, int noUnitsY, int xPos, int yPos, bool noRefresh ) { - int old_x = m_xScrollPixelsPerLine * m_xScrollPosition; - int old_y = m_yScrollPixelsPerLine * m_yScrollPosition; + int xs, ys; + GetViewStart (& xs, & ys); + + int old_x = m_xScrollPixelsPerLine * xs; + int old_y = m_yScrollPixelsPerLine * ys; m_xScrollPixelsPerLine = pixelsPerUnitX; m_yScrollPixelsPerLine = pixelsPerUnitY; @@ -351,9 +410,12 @@ void wxScrolledWindow::SetScrollbars( int pixelsPerUnitX, int pixelsPerUnitY, // Setting hints here should arguably be deprecated, but without it // a sizer might override this manual scrollbar setting in old code. - m_targetWindow->SetVirtualSizeHints( noUnitsX * pixelsPerUnitX, noUnitsY * pixelsPerUnitY ); + // m_targetWindow->SetVirtualSizeHints( noUnitsX * pixelsPerUnitX, noUnitsY * pixelsPerUnitY ); - m_targetWindow->SetVirtualSize( noUnitsX * pixelsPerUnitX, noUnitsY * pixelsPerUnitY ); + int w = noUnitsX * pixelsPerUnitX; + int h = noUnitsY * pixelsPerUnitY; + m_targetWindow->SetVirtualSize( w ? w : wxDefaultCoord, + h ? h : wxDefaultCoord); if (!noRefresh) { @@ -375,22 +437,31 @@ void wxScrolledWindow::AdjustScrollbars() if (m_xScrollPixelsPerLine == 0) { m_hAdjust->upper = 1.0; + m_hAdjust->page_increment = 1.0; m_hAdjust->page_size = 1.0; } else { - m_hAdjust->upper = vw / m_xScrollPixelsPerLine; - m_hAdjust->page_size = (w / m_xScrollPixelsPerLine); + m_hAdjust->upper = (vw+m_xScrollPixelsPerLine-1) / m_xScrollPixelsPerLine; + m_hAdjust->page_size = w / m_xScrollPixelsPerLine; + m_hAdjust->page_increment = w / m_xScrollPixelsPerLine; + + // Special case. When client and virtual size are very close but + // the client is big enough, kill scrollbar. + + if ((m_hAdjust->page_size < m_hAdjust->upper) && (w >= vw)) + m_hAdjust->page_size += 1.0; // If the scrollbar hits the right side, move the window // right to keep it from over extending. - if ((m_hAdjust->value != 0.0) && (m_hAdjust->value + m_hAdjust->page_size > m_hAdjust->upper)) + if ( !wxIsNullDouble(m_hAdjust->value) && + (m_hAdjust->value + m_hAdjust->page_size > m_hAdjust->upper) ) { m_hAdjust->value = m_hAdjust->upper - m_hAdjust->page_size; if (m_hAdjust->value < 0.0) m_hAdjust->value = 0.0; - + if (GetChildren().GetCount() == 0) m_xScrollPosition = (int)m_hAdjust->value; // This is enough without child windows else @@ -401,28 +472,34 @@ void wxScrolledWindow::AdjustScrollbars() if (m_yScrollPixelsPerLine == 0) { m_vAdjust->upper = 1.0; + m_vAdjust->page_increment = 1.0; m_vAdjust->page_size = 1.0; } else { - m_vAdjust->upper = vh / m_yScrollPixelsPerLine; - m_vAdjust->page_size = (h / m_yScrollPixelsPerLine); + m_vAdjust->upper = (vh+m_yScrollPixelsPerLine-1) / m_yScrollPixelsPerLine; + m_vAdjust->page_size = h / m_yScrollPixelsPerLine; + m_vAdjust->page_increment = h / m_yScrollPixelsPerLine; + + if ((m_vAdjust->page_size < m_vAdjust->upper) && (h >= vh)) + m_vAdjust->page_size += 1.0; - if ((m_vAdjust->value != 0.0) && (m_vAdjust->value + m_vAdjust->page_size > m_vAdjust->upper)) + if ( !wxIsNullDouble(m_vAdjust->value) && + (m_vAdjust->value + m_vAdjust->page_size > m_vAdjust->upper) ) { m_vAdjust->value = m_vAdjust->upper - m_vAdjust->page_size; if (m_vAdjust->value < 0.0) m_vAdjust->value = 0.0; - + if (GetChildren().GetCount() == 0) - m_yScrollPosition = (int)m_vAdjust->value; + m_yScrollPosition = (int)m_vAdjust->value; else gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" ); } } - m_xScrollLinesPerPage = (int)(m_hAdjust->page_size + 0.5); - m_yScrollLinesPerPage = (int)(m_vAdjust->page_size + 0.5); + m_xScrollLinesPerPage = (int)(m_hAdjust->page_increment + 0.5); + m_yScrollLinesPerPage = (int)(m_vAdjust->page_increment + 0.5); gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" ); gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" ); @@ -439,14 +516,14 @@ void wxScrolledWindow::SetTargetWindow( wxWindow *target, bool WXUNUSED(pushEven m_targetWindow = target; } -wxWindow *wxScrolledWindow::GetTargetWindow() +wxWindow *wxScrolledWindow::GetTargetWindow() const { return m_targetWindow; } // Override this function if you don't want to have wxScrolledWindow // automatically change the origin according to the scroll position. -void wxScrolledWindow::PrepareDC(wxDC& dc) +void wxScrolledWindow::DoPrepareDC(wxDC& dc) { dc.SetDeviceOrigin( -m_xScrollPosition * m_xScrollPixelsPerLine, -m_yScrollPosition * m_yScrollPixelsPerLine ); @@ -555,7 +632,7 @@ void wxScrolledWindow::Scroll( int x_pos, int y_pos ) m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 ); - // Just update the scrollbar, don't send any wxWindows event + // Just update the scrollbar, don't send any wxWidgets event GtkHDisconnectEvent(); gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); GtkHConnectEvent(); @@ -574,7 +651,7 @@ void wxScrolledWindow::Scroll( int x_pos, int y_pos ) m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine ); - // Just update the scrollbar, don't send any wxWindows event + // Just update the scrollbar, don't send any wxWidgets event GtkVDisconnectEvent(); gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" ); GtkVConnectEvent(); @@ -638,18 +715,24 @@ void wxScrolledWindow::GetViewStart (int *x, int *y) const void wxScrolledWindow::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) const { + int xs, ys; + GetViewStart (& xs, & ys); + if ( xx ) - *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine; + *xx = x - xs * m_xScrollPixelsPerLine; if ( yy ) - *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine; + *yy = y - ys * m_yScrollPixelsPerLine; } void wxScrolledWindow::DoCalcUnscrolledPosition(int x, int y, int *xx, int *yy) const { + int xs, ys; + GetViewStart (& xs, & ys); + if ( xx ) - *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine; + *xx = x + xs * m_xScrollPixelsPerLine; if ( yy ) - *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine; + *yy = y + ys * m_yScrollPixelsPerLine; } int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent& event) @@ -770,14 +853,14 @@ void wxScrolledWindow::SetScrollPos( int orient, int pos, bool refresh ) { if (orient == wxHORIZONTAL) { - // Just update the scrollbar, don't send any wxWindows event + // Just update the scrollbar, don't send any wxWidgets event GtkHDisconnectEvent(); gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); GtkHConnectEvent(); } else { - // Just update the scrollbar, don't send any wxWindows event + // Just update the scrollbar, don't send any wxWidgets event GtkVDisconnectEvent(); gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" ); GtkVConnectEvent(); @@ -833,12 +916,12 @@ bool wxScrolledWindow::Layout() // Default OnSize resets scrollbars, if any void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event)) { - if( GetAutoLayout() ) + if ( m_targetWindow->GetAutoLayout() ) { - if( m_targetWindow != this ) - m_targetWindow->FitInside(); + wxSize size = m_targetWindow->GetBestVirtualSize(); - FitInside(); + // This will call ::Layout() and ::AdjustScrollbars() + SetVirtualSize( size ); } else { @@ -941,19 +1024,19 @@ void wxScrolledWindow::OnChar(wxKeyEvent& event) int xScroll = GetScrollPos(wxHORIZONTAL); if ( xScroll != xScrollOld ) { - wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, xScroll, - wxHORIZONTAL); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + wxScrollWinEvent eventS(wxEVT_SCROLLWIN_THUMBTRACK, xScroll, + wxHORIZONTAL); + eventS.SetEventObject(this); + GetEventHandler()->ProcessEvent(eventS); } int yScroll = GetScrollPos(wxVERTICAL); if ( yScroll != yScrollOld ) { - wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, yScroll, - wxVERTICAL); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + wxScrollWinEvent eventS(wxEVT_SCROLLWIN_THUMBTRACK, yScroll, + wxVERTICAL); + eventS.SetEventObject(this); + GetEventHandler()->ProcessEvent(eventS); } }