X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0bc0cd5d8119c86b28760d1b18f6a08b98145979..f58fc1407b9d1f6db80943338714242d87b766d0:/src/gtk/scrolwin.cpp diff --git a/src/gtk/scrolwin.cpp b/src/gtk/scrolwin.cpp index 2de10148a0..9232d1e543 100644 --- a/src/gtk/scrolwin.cpp +++ b/src/gtk/scrolwin.cpp @@ -1,12 +1,12 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: generic/scrolwin.cpp +// Name: gtk/scrolwin.cpp // Purpose: wxScrolledWindow implementation // Author: Julian Smart -// Modified by: +// Modified by: Ron Lee // Created: 01/02/97 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Copyright: (c) Julian Smart +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -17,7 +17,7 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "scrolwin.h" #endif @@ -31,10 +31,11 @@ #include "wx/utils.h" #include "wx/dcclient.h" -#include "wx/gtk/scrolwin.h" +#include "wx/scrolwin.h" #include "wx/panel.h" +#include "wx/sizer.h" -#include +#include "wx/gtk/private.h" #include "wx/gtk/win_gtk.h" // ---------------------------------------------------------------------------- @@ -59,6 +60,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel) //----------------------------------------------------------------------------- extern bool g_blockEventsOnDrag; +extern bool g_blockEventsOnScroll; //----------------------------------------------------------------------------- // idle system @@ -71,7 +73,9 @@ extern bool g_isIdle; // "value_changed" from m_vAdjust //----------------------------------------------------------------------------- -static void gtk_scrolled_window_vscroll_callback( GtkAdjustment *adjust, wxScrolledWindow *win ) +static void gtk_scrolled_window_vscroll_callback( GtkAdjustment *adjust, + SCROLLBAR_CBACK_ARG + wxScrolledWindow *win ) { if (g_isIdle) wxapp_install_idle_handler(); @@ -80,14 +84,17 @@ static void gtk_scrolled_window_vscroll_callback( GtkAdjustment *adjust, wxScrol if (!win->m_hasVMT) return; - win->GtkVScroll( adjust->value ); + win->GtkVScroll( adjust->value, + GET_SCROLL_TYPE(GTK_SCROLLED_WINDOW(win->m_widget)->vscrollbar) ); } //----------------------------------------------------------------------------- // "value_changed" from m_hAdjust //----------------------------------------------------------------------------- -static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust, wxScrolledWindow *win ) +static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust, + SCROLLBAR_CBACK_ARG + wxScrolledWindow *win ) { if (g_isIdle) wxapp_install_idle_handler(); @@ -95,7 +102,72 @@ static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust, wxScrol if (g_blockEventsOnDrag) return; if (!win->m_hasVMT) return; - win->GtkHScroll( adjust->value ); + win->GtkHScroll( adjust->value, + GET_SCROLL_TYPE(GTK_SCROLLED_WINDOW(win->m_widget)->hscrollbar) ); +} + +//----------------------------------------------------------------------------- +// "button_press_event" from scrollbar +//----------------------------------------------------------------------------- + +static gint gtk_scrollbar_button_press_callback( GtkRange *widget, + GdkEventButton *gdk_event, + wxWindowGTK *win) +{ + if (g_isIdle) + wxapp_install_idle_handler(); + + g_blockEventsOnScroll = TRUE; + + // FIXME: there is no slider field any more, what was meant here? +#ifndef __WXGTK20__ + win->m_isScrolling = (gdk_event->window == widget->slider); +#endif + + return FALSE; +} + +//----------------------------------------------------------------------------- +// "button_release_event" from scrollbar +//----------------------------------------------------------------------------- + +static gint gtk_scrollbar_button_release_callback( GtkRange *widget, + GdkEventButton *WXUNUSED(gdk_event), + wxWindowGTK *win) +{ +// don't test here as we can release the mouse while being over +// a different window than the slider +// +// if (gdk_event->window != widget->slider) return FALSE; + + g_blockEventsOnScroll = FALSE; + + if (win->m_isScrolling) + { + wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE; + int value = -1; + int dir = -1; + + GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget); + if (widget == GTK_RANGE(scrolledWindow->hscrollbar)) + { + value = (int)(win->m_hAdjust->value+0.5); + dir = wxHORIZONTAL; + } + if (widget == GTK_RANGE(scrolledWindow->vscrollbar)) + { + value = (int)(win->m_vAdjust->value+0.5); + dir = wxVERTICAL; + } + + wxScrollWinEvent event( command, value, dir ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); + } + + win->m_isScrolling = FALSE; + + return FALSE; } //----------------------------------------------------------------------------- @@ -104,8 +176,8 @@ static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust, wxScrol static void wxInsertChildInScrolledWindow( wxWindow* parent, wxWindow* child ) { - /* the window might have been scrolled already, do we - have to adapt the position */ + // The window might have been scrolled already, do we + // have to adapt the position. GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow); child->m_x += pizza->xoffset; child->m_y += pizza->yoffset; @@ -122,7 +194,7 @@ static void wxInsertChildInScrolledWindow( wxWindow* parent, wxWindow* child ) // wxScrolledWindow creation // ---------------------------------------------------------------------------- -wxScrolledWindow::wxScrolledWindow() +void wxScrolledWindow::Init() { m_xScrollPixelsPerLine = 0; m_yScrollPixelsPerLine = 0; @@ -130,13 +202,12 @@ wxScrolledWindow::wxScrolledWindow() m_yScrollingEnabled = TRUE; m_xScrollPosition = 0; m_yScrollPosition = 0; - m_xScrollLines = 0; - m_yScrollLines = 0; m_xScrollLinesPerPage = 0; m_yScrollLinesPerPage = 0; m_targetWindow = (wxWindow*) NULL; m_scaleX = 1.0; m_scaleY = 1.0; + m_hasScrolling = TRUE; } bool wxScrolledWindow::Create(wxWindow *parent, @@ -146,6 +217,8 @@ bool wxScrolledWindow::Create(wxWindow *parent, long style, const wxString& name) { + Init(); + if (!PreCreation( parent, pos, size ) || !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name )) { @@ -154,17 +227,6 @@ bool wxScrolledWindow::Create(wxWindow *parent, } m_insertCallback = wxInsertChildInScrolledWindow; - - m_xScrollPixelsPerLine = 0; - m_yScrollPixelsPerLine = 0; - m_xScrollingEnabled = TRUE; - m_yScrollingEnabled = TRUE; - m_xScrollPosition = 0; - m_yScrollPosition = 0; - m_xScrollLines = 0; - m_yScrollLines = 0; - m_xScrollLinesPerPage = 0; - m_yScrollLinesPerPage = 0; m_targetWindow = this; @@ -212,100 +274,169 @@ bool wxScrolledWindow::Create(wxWindow *parent, m_vAdjust->upper = 1.0; m_vAdjust->value = 0.0; m_vAdjust->step_increment = 1.0; - m_vAdjust->page_increment = 1.0; + m_vAdjust->page_increment = 2.0; gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" ); m_hAdjust->lower = 0.0; m_hAdjust->upper = 1.0; m_hAdjust->value = 0.0; m_hAdjust->step_increment = 1.0; - m_hAdjust->page_increment = 1.0; + m_hAdjust->page_increment = 2.0; gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" ); - // these handlers get notified when screen updates are required either when - // scrolling or when the window size (and therefore scrollbar configuration) - // has changed - gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed", - (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this ); - gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed", - (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this ); + // Handlers for new scrollbar values + GtkVConnectEvent(); + 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 + // slider should be + + gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event", + (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event", + (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event", + (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event", + (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this ); gtk_widget_show( m_wxwindow ); if (m_parent) m_parent->DoAddChild( this ); + m_focusWidget = m_wxwindow; + PostCreation(); Show( TRUE ); - + return TRUE; } -wxScrolledWindow::~wxScrolledWindow() -{ -} - // ---------------------------------------------------------------------------- // setting scrolling parameters // ---------------------------------------------------------------------------- +void wxScrolledWindow::DoSetVirtualSize( int x, int y ) +{ + wxPanel::DoSetVirtualSize( x, y ); + AdjustScrollbars(); + +#if wxUSE_CONSTRAINTS + if (GetAutoLayout()) + Layout(); +#endif +} + /* * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line) * noUnitsX/noUnitsY: : no. units per scrollbar */ -void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX, int pixelsPerUnitY, - int noUnitsX, int noUnitsY, - int xPos, int yPos, bool noRefresh ) +void wxScrolledWindow::SetScrollbars( int pixelsPerUnitX, int pixelsPerUnitY, + int noUnitsX, int noUnitsY, + int xPos, int yPos, bool noRefresh ) { + int xs, ys; + GetViewStart (& xs, & ys); + + int old_x = m_xScrollPixelsPerLine * xs; + int old_y = m_yScrollPixelsPerLine * ys; + m_xScrollPixelsPerLine = pixelsPerUnitX; m_yScrollPixelsPerLine = pixelsPerUnitY; - m_xScrollPosition = xPos; - m_yScrollPosition = yPos; - m_xScrollLines = noUnitsX; - m_yScrollLines = noUnitsY; - - m_hAdjust->lower = 0.0; - m_hAdjust->upper = noUnitsX; - m_hAdjust->value = xPos; - m_hAdjust->step_increment = 1.0; - m_hAdjust->page_increment = 2.0; - m_vAdjust->lower = 0.0; - m_vAdjust->upper = noUnitsY; - m_vAdjust->value = yPos; - m_vAdjust->step_increment = 1.0; - m_vAdjust->page_increment = 2.0; - - AdjustScrollbars(); + m_hAdjust->value = m_xScrollPosition = xPos; + m_vAdjust->value = m_yScrollPosition = yPos; + + // 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->SetVirtualSize( noUnitsX * pixelsPerUnitX, noUnitsY * pixelsPerUnitY ); + + if (!noRefresh) + { + int new_x = m_xScrollPixelsPerLine * m_xScrollPosition; + int new_y = m_yScrollPixelsPerLine * m_yScrollPosition; + + m_targetWindow->ScrollWindow( old_x - new_x, old_y - new_y ); + } } void wxScrolledWindow::AdjustScrollbars() { int w, h; + int vw, vh; + m_targetWindow->GetClientSize( &w, &h ); - + m_targetWindow->GetVirtualSize( &vw, &vh ); + if (m_xScrollPixelsPerLine == 0) + { + m_hAdjust->upper = 1.0; m_hAdjust->page_size = 1.0; + } else + { + m_hAdjust->upper = vw / m_xScrollPixelsPerLine; m_hAdjust->page_size = (w / m_xScrollPixelsPerLine); - + + // 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)) + { + 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 + gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); // Actually scroll window + } + } + if (m_yScrollPixelsPerLine == 0) + { + m_vAdjust->upper = 1.0; m_vAdjust->page_size = 1.0; + } else + { + m_vAdjust->upper = vh / m_yScrollPixelsPerLine; m_vAdjust->page_size = (h / m_yScrollPixelsPerLine); - + + if ((m_vAdjust->value != 0.0) && (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; + 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); - + gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" ); gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" ); } + // ---------------------------------------------------------------------------- // target window handling // ---------------------------------------------------------------------------- -void wxScrolledWindow::SetTargetWindow( wxWindow *target ) +void wxScrolledWindow::SetTargetWindow( wxWindow *target, bool WXUNUSED(pushEventHandler) ) { wxASSERT_MSG( target, wxT("target window must not be NULL") ); m_targetWindow = target; @@ -324,6 +455,22 @@ void wxScrolledWindow::PrepareDC(wxDC& dc) -m_yScrollPosition * m_yScrollPixelsPerLine ); } +void wxScrolledWindow::SetScrollRate( int xstep, int ystep ) +{ + int old_x = m_xScrollPixelsPerLine * m_xScrollPosition; + int old_y = m_yScrollPixelsPerLine * m_yScrollPosition; + + m_xScrollPixelsPerLine = xstep; + m_yScrollPixelsPerLine = ystep; + + int new_x = m_xScrollPixelsPerLine * m_xScrollPosition; + int new_y = m_yScrollPixelsPerLine * m_yScrollPosition; + + m_targetWindow->ScrollWindow( old_x - new_x, old_y - new_y ); + + AdjustScrollbars(); +} + void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const { if ( x_unit ) @@ -393,111 +540,88 @@ void wxScrolledWindow::OnScroll(wxScrollWinEvent& event) void wxScrolledWindow::Scroll( int x_pos, int y_pos ) { - if (!m_targetWindow) - return; + wxASSERT_MSG( m_targetWindow != 0, _T("No target window") ); if (((x_pos == -1) || (x_pos == m_xScrollPosition)) && ((y_pos == -1) || (y_pos == m_yScrollPosition))) return; if ((x_pos != -1) && (m_xScrollPixelsPerLine)) { + int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5); + if (max < 0) max = 0; + if (x_pos > max) x_pos = max; + if (x_pos < 0) x_pos = 0; + int old_x = m_xScrollPosition; m_xScrollPosition = x_pos; m_hAdjust->value = x_pos; - - wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; - wxScrollWinEvent event( command, m_xScrollPosition, wxHORIZONTAL ); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent( event ); - + m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 ); - + + // Just update the scrollbar, don't send any wxWindows event + GtkHDisconnectEvent(); gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); + GtkHConnectEvent(); } - + if ((y_pos != -1) && (m_yScrollPixelsPerLine)) { + int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5); + if (max < 0) max = 0; + if (y_pos > max) y_pos = max; + if (y_pos < 0) y_pos = 0; + int old_y = m_yScrollPosition; m_yScrollPosition = y_pos; m_vAdjust->value = y_pos; - - wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; - wxScrollWinEvent event( command, m_yScrollPosition, wxVERTICAL ); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent( event ); - + m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine ); - + + // Just update the scrollbar, don't send any wxWindows event + GtkVDisconnectEvent(); gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" ); + GtkVConnectEvent(); } } -void wxScrolledWindow::GtkVScroll( float value ) +// TODO: [VH]Scroll functions should be combined + +void wxScrolledWindow::GtkVScroll( float value, unsigned int scroll_type ) { - if (!m_targetWindow) - return; + wxASSERT_MSG( m_targetWindow != 0, _T("No target window") ); if (m_yScrollPixelsPerLine == 0) return; - + int y_pos = (int)(value+0.5); - + if (y_pos == m_yScrollPosition) return; - - GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget); - GtkRange *range = GTK_RANGE(scrolledWindow->vscrollbar); - - wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; - if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP; - else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN; - else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP; - else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN; + + wxEventType command = GtkScrollWinTypeToWx(scroll_type); wxScrollWinEvent event( command, y_pos, wxVERTICAL ); event.SetEventObject( this ); GetEventHandler()->ProcessEvent( event ); - -/* - int old_y = m_yScrollPosition; - m_yScrollPosition = y_pos; - - m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine ); -*/ } -void wxScrolledWindow::GtkHScroll( float value ) +void wxScrolledWindow::GtkHScroll( float value, unsigned int scroll_type ) { - if (!m_targetWindow) - return; - + wxASSERT_MSG( m_targetWindow != 0, _T("No target window") ); + if (m_xScrollPixelsPerLine == 0) return; - + int x_pos = (int)(value+0.5); if (x_pos == m_xScrollPosition) return; - GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget); - GtkRange *range = GTK_RANGE(scrolledWindow->hscrollbar); - - wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; - if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP; - else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN; - else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP; - else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN; + wxEventType command = GtkScrollWinTypeToWx(scroll_type); wxScrollWinEvent event( command, x_pos, wxHORIZONTAL ); event.SetEventObject( this ); GetEventHandler()->ProcessEvent( event ); - -/* - int old_x = m_xScrollPosition; - m_xScrollPosition = x_pos; - - m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 ); -*/ } void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll) @@ -506,14 +630,6 @@ void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll) m_yScrollingEnabled = y_scroll; } -void wxScrolledWindow::GetVirtualSize (int *x, int *y) const -{ - if ( x ) - *x = m_xScrollPixelsPerLine * m_xScrollLines; - if ( y ) - *y = m_yScrollPixelsPerLine * m_yScrollLines; -} - // Where the current view starts from void wxScrolledWindow::GetViewStart (int *x, int *y) const { @@ -523,20 +639,26 @@ void wxScrolledWindow::GetViewStart (int *x, int *y) const *y = m_yScrollPosition; } -void wxScrolledWindow::CalcScrolledPosition(int x, int y, int *xx, int *yy) 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::CalcUnscrolledPosition(int x, int y, int *xx, int *yy) const +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) @@ -555,9 +677,9 @@ int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent& event) if (event.GetEventType() == wxEVT_SCROLLWIN_BOTTOM) { if (orient == wxHORIZONTAL) - nScrollInc = m_xScrollLines - m_xScrollPosition; + nScrollInc = GetVirtualSize().GetWidth() / m_xScrollPixelsPerLine - m_xScrollPosition; else - nScrollInc = m_yScrollLines - m_yScrollPosition; + nScrollInc = GetVirtualSize().GetHeight() / m_yScrollPixelsPerLine - m_yScrollPosition; } else if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP) { @@ -594,16 +716,13 @@ int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent& event) { if (m_xScrollPixelsPerLine > 0) { - int w, h; - m_targetWindow->GetClientSize(&w, &h); - - int noPositions = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5); - if (noPositions < 0) noPositions = 0; + int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5); + if (max < 0) max = 0; if ( (m_xScrollPosition + nScrollInc) < 0 ) nScrollInc = -m_xScrollPosition; // As -ve as we can go - else if ( (m_xScrollPosition + nScrollInc) > noPositions ) - nScrollInc = noPositions - m_xScrollPosition; // As +ve as we can go + else if ( (m_xScrollPosition + nScrollInc) > max ) + nScrollInc = max - m_xScrollPosition; // As +ve as we can go } else m_targetWindow->Refresh(); @@ -612,16 +731,13 @@ int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent& event) { if (m_yScrollPixelsPerLine > 0) { - int w, h; - m_targetWindow->GetClientSize(&w, &h); - - int noPositions = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5); - if (noPositions < 0) noPositions = 0; + int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5); + if (max < 0) max = 0; if ( (m_yScrollPosition + nScrollInc) < 0 ) nScrollInc = -m_yScrollPosition; // As -ve as we can go - else if ( (m_yScrollPosition + nScrollInc) > noPositions ) - nScrollInc = noPositions - m_yScrollPosition; // As +ve as we can go + else if ( (m_yScrollPosition + nScrollInc) > max ) + nScrollInc = max - m_yScrollPosition; // As +ve as we can go } else m_targetWindow->Refresh(); @@ -630,7 +746,7 @@ int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent& event) return nScrollInc; } -void wxScrolledWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) ) +void wxScrolledWindow::SetScrollPos( int orient, int pos, bool refresh ) { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); @@ -638,48 +754,87 @@ void wxScrolledWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) if (orient == wxHORIZONTAL) { - float fpos = (float)pos; - if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size; - if (fpos < 0.0) fpos = 0.0; + int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5); + if (max < 0) max = 0; + + if (pos > max) pos = 0; + if (pos < 0) pos = 0; - if (fabs(fpos-m_hAdjust->value) < 0.2) return; - m_hAdjust->value = fpos; + if (pos == (int)(m_hAdjust->value+0.5)) return; + m_hAdjust->value = pos; } else { - float fpos = (float)pos; - if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size; - if (fpos < 0.0) fpos = 0.0; + int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5); + if (max < 0) max = 0; - if (fabs(fpos-m_vAdjust->value) < 0.2) return; - m_vAdjust->value = fpos; + if (pos > max) pos = 0; + if (pos < 0) pos = 0; + + if (pos == (int)(m_vAdjust->value+0.5)) return; + m_vAdjust->value = pos; } if (m_wxwindow->window) { if (orient == wxHORIZONTAL) { - gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust), - (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this ); - + // Just update the scrollbar, don't send any wxWindows event + GtkHDisconnectEvent(); gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); - - gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed", - (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this ); + GtkHConnectEvent(); } else { - gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust), - (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this ); - + // Just update the scrollbar, don't send any wxWindows event + GtkVDisconnectEvent(); gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" ); - - gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed", - (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this ); + GtkVConnectEvent(); } } } +void wxScrolledWindow::GtkVConnectEvent() +{ + gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed", + (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this ); +} + +void wxScrolledWindow::GtkHConnectEvent() +{ + gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed", + (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this ); +} + +void wxScrolledWindow::GtkHDisconnectEvent() +{ + gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust), + (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this ); +} + +void wxScrolledWindow::GtkVDisconnectEvent() +{ + gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust), + (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this ); +} + +bool wxScrolledWindow::Layout() +{ + if (GetSizer() && m_targetWindow == this) + { + // If we're the scroll target, take into account the + // virtual size and scrolled position of the window. + + int x, y, w, h; + CalcScrolledPosition(0,0, &x,&y); + GetVirtualSize(&w, &h); + GetSizer()->SetDimension(x, y, w, h); + return TRUE; + } + else + return wxPanel::Layout(); // fall back to default for LayoutConstraints +} + // ---------------------------------------------------------------------------- // event handlers // ---------------------------------------------------------------------------- @@ -687,12 +842,24 @@ void wxScrolledWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) // Default OnSize resets scrollbars, if any void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event)) { -#if wxUSE_CONSTRAINTS - if (GetAutoLayout()) - Layout(); -#endif + if( GetAutoLayout() || m_targetWindow->GetAutoLayout() ) + { + if( m_targetWindow != this ) + m_targetWindow->FitInside(); - AdjustScrollbars(); + FitInside(); + + // FIXME: Something is really weird here... This should be + // called by FitInside above (and apparently is), yet the + // scrollsub sample will get the scrollbar wrong if resized + // quickly. This masks the bug, but is surely not the right + // answer at all. + AdjustScrollbars(); + } + else + { + AdjustScrollbars(); + } } // This calls OnDraw, having adjusted the origin according to the current @@ -715,7 +882,7 @@ void wxScrolledWindow::OnChar(wxKeyEvent& event) szx, szy, // view size (total) clix, cliy; // view size (on screen) - ViewStart(&stx, &sty); + GetViewStart(&stx, &sty); GetClientSize(&clix, &cliy); GetVirtualSize(&szx, &szy); @@ -740,8 +907,11 @@ void wxScrolledWindow::OnChar(wxKeyEvent& event) szy = -1; } + int xScrollOld = GetScrollPos(wxHORIZONTAL), + yScrollOld = GetScrollPos(wxVERTICAL); + int dsty; - switch ( event.KeyCode() ) + switch ( event.GetKeyCode() ) { case WXK_PAGEUP: case WXK_PRIOR: @@ -781,5 +951,27 @@ void wxScrolledWindow::OnChar(wxKeyEvent& event) default: // not for us event.Skip(); + return; + } + + int xScroll = GetScrollPos(wxHORIZONTAL); + if ( xScroll != xScrollOld ) + { + wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, xScroll, + wxHORIZONTAL); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } + + int yScroll = GetScrollPos(wxVERTICAL); + if ( yScroll != yScrollOld ) + { + wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, yScroll, + wxVERTICAL); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); } } + + +// vi:sts=4:sw=4:et