X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9fa72bd2a637cee761c56e2ce61cec3e43c62765..11a23db53128bf244a089123b7fd27deb577a889:/src/gtk/scrolwin.cpp diff --git a/src/gtk/scrolwin.cpp b/src/gtk/scrolwin.cpp index 001017f731..9b39077a3d 100644 --- a/src/gtk/scrolwin.cpp +++ b/src/gtk/scrolwin.cpp @@ -1,23 +1,14 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: gtk/scrolwin.cpp +// Name: src/gtk/scrolwin.cpp // Purpose: wxScrolledWindow implementation // Author: Robert Roebling // Modified by: Ron Lee // Vadim Zeitlin: removed 90% of duplicated common code // Created: 01/02/97 -// RCS-ID: $Id$ // Copyright: (c) Robert Roebling // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -26,156 +17,194 @@ #endif #include "wx/scrolwin.h" -#include "wx/gtk/private.h" -// ============================================================================ -// implementation -// ============================================================================ +#include +#include "wx/gtk/private/gtk2-compat.h" // ---------------------------------------------------------------------------- // wxScrollHelper implementation // ---------------------------------------------------------------------------- -void wxScrollHelperNative::SetScrollbars(int pixelsPerUnitX, int pixelsPerUnitY, - int noUnitsX, int noUnitsY, - int xPos, int yPos, - bool noRefresh) +void wxScrollHelper::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_win->m_hAdjust->value = m_xScrollPosition = xPos; - m_win->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 ); - - int w = noUnitsX * pixelsPerUnitX; - int h = noUnitsY * pixelsPerUnitY; - m_targetWindow->SetVirtualSize( w ? w : wxDefaultCoord, - h ? h : wxDefaultCoord); - - 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 ); - } + // prevent programmatic position changes from causing scroll events + m_win->SetScrollPos(wxHORIZONTAL, xPos); + m_win->SetScrollPos(wxVERTICAL, yPos); - m_targetWindow->m_hasScrolling = pixelsPerUnitX || pixelsPerUnitY; + base_type::SetScrollbars( + pixelsPerUnitX, pixelsPerUnitY, noUnitsX, noUnitsY, xPos, yPos, noRefresh); } -void wxScrollHelperNative::DoAdjustScrollbar(GtkAdjustment *adj, - int pixelsPerLine, - int winSize, - int virtSize, - int *pos, - int *lines, - int *linesPerPage) +void wxScrollHelper::DoAdjustScrollbar(GtkRange* range, + int pixelsPerLine, + int winSize, + int virtSize, + int *pos, + int *lines, + int *linesPerPage) { - if ( pixelsPerLine == 0 ) + if (!range) + return; + + int upper; + int page_size; + if (pixelsPerLine > 0 && winSize > 0 && winSize < virtSize) { - adj->upper = 1.0; - adj->page_increment = 1.0; - adj->page_size = 1.0; + upper = (virtSize + pixelsPerLine - 1) / pixelsPerLine; + page_size = winSize / pixelsPerLine; + *lines = upper; + *linesPerPage = page_size; } - else // we do have scrollbar + else { - adj->upper = (virtSize + pixelsPerLine - 1) / pixelsPerLine; - adj->page_size = winSize / pixelsPerLine; - adj->page_increment = winSize / pixelsPerLine; - - // Special case. When client and virtual size are very close but - // the client is big enough, kill scrollbar. - - if ((adj->page_size < adj->upper) && (winSize >= virtSize)) - adj->page_size += 1.0; - - // If the scrollbar hits the right side, move the window - // right to keep it from over extending. - - if ( !wxIsNullDouble(adj->value) && - (adj->value + adj->page_size > adj->upper) ) - { - adj->value = adj->upper - adj->page_size; - if (adj->value < 0.0) - adj->value = 0.0; - - if ( m_win->GetChildren().empty() ) - { - // This is enough without child windows - *pos = (int)adj->value; - } - else - { - // We need to actually scroll window - g_signal_emit_by_name (adj, "value_changed"); - } - } + // GtkRange won't allow upper == lower, so for disabled state use [0,1] + // with a page size of 1. This will also clamp position to 0. + upper = 1; + page_size = 1; + *lines = 0; + *linesPerPage = 0; } - *lines = (int)(adj->upper + 0.5); - *linesPerPage = (int)(adj->page_increment + 0.5); - g_signal_emit_by_name (adj, "changed"); + gtk_range_set_increments(range, 1, page_size); + gtk_adjustment_set_page_size(gtk_range_get_adjustment(range), page_size); + gtk_range_set_range(range, 0, upper); + + // ensure that the scroll position is always in valid range + if (*pos > *lines) + *pos = *lines; } -void wxScrollHelperNative::AdjustScrollbars() +void wxScrollHelper::AdjustScrollbars() { - int w, h; int vw, vh; + m_targetWindow->GetVirtualSize(&vw, &vh); - m_targetWindow->GetClientSize( &w, &h ); - m_targetWindow->GetVirtualSize( &vw, &vh ); + int w, h; + const wxSize availSize = GetSizeAvailableForScrollTarget( + m_win->GetSize() - m_win->GetWindowBorderSize()); + if ( availSize.x >= vw && availSize.y >= vh ) + { + w = availSize.x; + h = availSize.y; + + // we know that the scrollbars will be removed + DoAdjustHScrollbar(w, vw); + DoAdjustVScrollbar(h, vh); - DoAdjustScrollbar(m_win->m_hAdjust, m_xScrollPixelsPerLine, w, vw, - &m_xScrollPosition, &m_xScrollLines, &m_xScrollLinesPerPage); - DoAdjustScrollbar(m_win->m_vAdjust, m_yScrollPixelsPerLine, h, vh, - &m_yScrollPosition, &m_yScrollLines, &m_yScrollLinesPerPage); + return; + } + + m_targetWindow->GetClientSize(&w, NULL); + DoAdjustHScrollbar(w, vw); + + m_targetWindow->GetClientSize(NULL, &h); + DoAdjustVScrollbar(h, vh); + + const int w_old = w; + m_targetWindow->GetClientSize(&w, NULL); + if ( w != w_old ) + { + // It is necessary to repeat the calculations in this case to avoid an + // observed infinite series of size events, involving alternating + // changes in visibility of the scrollbars. + // At this point, GTK+ has already queued a resize, which will cause + // AdjustScrollbars() to be called again. If the scrollbar visibility + // is not correct before then, yet another resize will occur, possibly + // leading to an unending series if the sizes are just right. + DoAdjustHScrollbar(w, vw); + + m_targetWindow->GetClientSize(NULL, &h); + DoAdjustVScrollbar(h, vh); + } } -void wxScrollHelperNative::DoScroll(int orient, - GtkAdjustment *adj, +void wxScrollHelper::DoScrollOneDir(int orient, int pos, int pixelsPerLine, int *posOld) { if ( pos != -1 && pos != *posOld && pixelsPerLine ) { - int max = (int)(adj->upper - adj->page_size + 0.5); - if (max < 0) - max = 0; - if (pos > max) - pos = max; - if (pos < 0) - pos = 0; - - adj->value = pos; + m_win->SetScrollPos(orient, pos); + pos = m_win->GetScrollPos(orient); int diff = (*posOld - pos)*pixelsPerLine; m_targetWindow->ScrollWindow(orient == wxHORIZONTAL ? diff : 0, orient == wxHORIZONTAL ? 0 : diff); *posOld = pos; + } +} + +void wxScrollHelper::DoScroll( int x_pos, int y_pos ) +{ + wxCHECK_RET( m_targetWindow != 0, wxT("No target window") ); - m_win->GtkUpdateScrollbar(orient); + DoScrollOneDir(wxHORIZONTAL, x_pos, m_xScrollPixelsPerLine, &m_xScrollPosition); + DoScrollOneDir(wxVERTICAL, y_pos, m_yScrollPixelsPerLine, &m_yScrollPosition); +} + +// ---------------------------------------------------------------------------- +// scrollbars visibility +// ---------------------------------------------------------------------------- + +namespace +{ + +GtkPolicyType GtkPolicyFromWX(wxScrollbarVisibility visibility) +{ + GtkPolicyType policy; + switch ( visibility ) + { + case wxSHOW_SB_NEVER: + policy = GTK_POLICY_NEVER; + break; + + case wxSHOW_SB_DEFAULT: + policy = GTK_POLICY_AUTOMATIC; + break; + + default: + wxFAIL_MSG( wxS("unknown scrollbar visibility") ); + // fall through + + case wxSHOW_SB_ALWAYS: + policy = GTK_POLICY_ALWAYS; + break; } + + return policy; } -void wxScrollHelperNative::Scroll( int x_pos, int y_pos ) +} // anonymous namespace + +bool wxScrollHelper::IsScrollbarShown(int orient) const { - wxCHECK_RET( m_targetWindow != 0, _T("No target window") ); + GtkScrolledWindow * const scrolled = GTK_SCROLLED_WINDOW(m_win->m_widget); + if ( !scrolled ) + { + // By default, all windows are scrollable. + return true; + } + + GtkPolicyType hpolicy, vpolicy; + gtk_scrolled_window_get_policy(scrolled, &hpolicy, &vpolicy); + + GtkPolicyType policy = orient == wxHORIZONTAL ? hpolicy : vpolicy; - DoScroll(wxHORIZONTAL, m_win->m_hAdjust, x_pos, m_xScrollPixelsPerLine, - &m_xScrollPosition); - DoScroll(wxVERTICAL, m_win->m_vAdjust, y_pos, m_yScrollPixelsPerLine, - &m_yScrollPosition); + return policy != GTK_POLICY_NEVER; } +void wxScrollHelper::DoShowScrollbars(wxScrollbarVisibility horz, + wxScrollbarVisibility vert) +{ + GtkScrolledWindow * const scrolled = GTK_SCROLLED_WINDOW(m_win->m_widget); + wxCHECK_RET( scrolled, "window must be created" ); + + gtk_scrolled_window_set_policy(scrolled, + GtkPolicyFromWX(horz), + GtkPolicyFromWX(vert)); +}