Make wxWindow::HasScrollbar() respect wxScrolled::ShowScrollbars().
[wxWidgets.git] / src / gtk / scrolwin.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/scrolwin.cpp
3 // Purpose: wxScrolledWindow implementation
4 // Author: Robert Roebling
5 // Modified by: Ron Lee
6 // Vadim Zeitlin: removed 90% of duplicated common code
7 // Created: 01/02/97
8 // Copyright: (c) Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #include "wx/scrolwin.h"
20
21 #include <gtk/gtk.h>
22 #include "wx/gtk/private/gtk2-compat.h"
23
24 // ----------------------------------------------------------------------------
25 // wxScrollHelper implementation
26 // ----------------------------------------------------------------------------
27
28 void wxScrollHelper::SetScrollbars(int pixelsPerUnitX, int pixelsPerUnitY,
29 int noUnitsX, int noUnitsY,
30 int xPos, int yPos,
31 bool noRefresh)
32 {
33 // prevent programmatic position changes from causing scroll events
34 m_win->SetScrollPos(wxHORIZONTAL, xPos);
35 m_win->SetScrollPos(wxVERTICAL, yPos);
36
37 base_type::SetScrollbars(
38 pixelsPerUnitX, pixelsPerUnitY, noUnitsX, noUnitsY, xPos, yPos, noRefresh);
39 }
40
41 void wxScrollHelper::DoAdjustScrollbar(GtkRange* range,
42 int pixelsPerLine,
43 int winSize,
44 int virtSize,
45 int *pos,
46 int *lines,
47 int *linesPerPage)
48 {
49 if (!range)
50 return;
51
52 int upper;
53 int page_size;
54 if (pixelsPerLine > 0 && winSize > 0 && winSize < virtSize)
55 {
56 upper = (virtSize + pixelsPerLine - 1) / pixelsPerLine;
57 page_size = winSize / pixelsPerLine;
58 *lines = upper;
59 *linesPerPage = page_size;
60 }
61 else
62 {
63 // GtkRange won't allow upper == lower, so for disabled state use [0,1]
64 // with a page size of 1. This will also clamp position to 0.
65 upper = 1;
66 page_size = 1;
67 *lines = 0;
68 *linesPerPage = 0;
69 }
70
71 gtk_range_set_increments(range, 1, page_size);
72 gtk_adjustment_set_page_size(gtk_range_get_adjustment(range), page_size);
73 gtk_range_set_range(range, 0, upper);
74
75 // ensure that the scroll position is always in valid range
76 if (*pos > *lines)
77 *pos = *lines;
78 }
79
80 void wxScrollHelper::AdjustScrollbars()
81 {
82 int vw, vh;
83 m_targetWindow->GetVirtualSize(&vw, &vh);
84
85 int w, h;
86 const wxSize availSize = GetSizeAvailableForScrollTarget(
87 m_win->GetSize() - m_win->GetWindowBorderSize());
88 if ( availSize.x >= vw && availSize.y >= vh )
89 {
90 w = availSize.x;
91 h = availSize.y;
92
93 // we know that the scrollbars will be removed
94 DoAdjustHScrollbar(w, vw);
95 DoAdjustVScrollbar(h, vh);
96
97 return;
98 }
99
100 m_targetWindow->GetClientSize(&w, NULL);
101 DoAdjustHScrollbar(w, vw);
102
103 m_targetWindow->GetClientSize(NULL, &h);
104 DoAdjustVScrollbar(h, vh);
105
106 const int w_old = w;
107 m_targetWindow->GetClientSize(&w, NULL);
108 if ( w != w_old )
109 {
110 // It is necessary to repeat the calculations in this case to avoid an
111 // observed infinite series of size events, involving alternating
112 // changes in visibility of the scrollbars.
113 // At this point, GTK+ has already queued a resize, which will cause
114 // AdjustScrollbars() to be called again. If the scrollbar visibility
115 // is not correct before then, yet another resize will occur, possibly
116 // leading to an unending series if the sizes are just right.
117 DoAdjustHScrollbar(w, vw);
118
119 m_targetWindow->GetClientSize(NULL, &h);
120 DoAdjustVScrollbar(h, vh);
121 }
122 }
123
124 void wxScrollHelper::DoScrollOneDir(int orient,
125 int pos,
126 int pixelsPerLine,
127 int *posOld)
128 {
129 if ( pos != -1 && pos != *posOld && pixelsPerLine )
130 {
131 m_win->SetScrollPos(orient, pos);
132 pos = m_win->GetScrollPos(orient);
133
134 int diff = (*posOld - pos)*pixelsPerLine;
135 m_targetWindow->ScrollWindow(orient == wxHORIZONTAL ? diff : 0,
136 orient == wxHORIZONTAL ? 0 : diff);
137
138 *posOld = pos;
139 }
140 }
141
142 void wxScrollHelper::DoScroll( int x_pos, int y_pos )
143 {
144 wxCHECK_RET( m_targetWindow != 0, wxT("No target window") );
145
146 DoScrollOneDir(wxHORIZONTAL, x_pos, m_xScrollPixelsPerLine, &m_xScrollPosition);
147 DoScrollOneDir(wxVERTICAL, y_pos, m_yScrollPixelsPerLine, &m_yScrollPosition);
148 }
149
150 // ----------------------------------------------------------------------------
151 // scrollbars visibility
152 // ----------------------------------------------------------------------------
153
154 namespace
155 {
156
157 GtkPolicyType GtkPolicyFromWX(wxScrollbarVisibility visibility)
158 {
159 GtkPolicyType policy;
160 switch ( visibility )
161 {
162 case wxSHOW_SB_NEVER:
163 policy = GTK_POLICY_NEVER;
164 break;
165
166 case wxSHOW_SB_DEFAULT:
167 policy = GTK_POLICY_AUTOMATIC;
168 break;
169
170 default:
171 wxFAIL_MSG( wxS("unknown scrollbar visibility") );
172 // fall through
173
174 case wxSHOW_SB_ALWAYS:
175 policy = GTK_POLICY_ALWAYS;
176 break;
177 }
178
179 return policy;
180 }
181
182 } // anonymous namespace
183
184 bool wxScrollHelper::IsScrollbarShown(int orient) const
185 {
186 GtkScrolledWindow * const scrolled = GTK_SCROLLED_WINDOW(m_win->m_widget);
187 if ( !scrolled )
188 {
189 // By default, all windows are scrollable.
190 return true;
191 }
192
193 GtkPolicyType hpolicy, vpolicy;
194 gtk_scrolled_window_get_policy(scrolled, &hpolicy, &vpolicy);
195
196 GtkPolicyType policy = orient == wxHORIZONTAL ? hpolicy : vpolicy;
197
198 return policy != GTK_POLICY_NEVER;
199 }
200
201 void wxScrollHelper::DoShowScrollbars(wxScrollbarVisibility horz,
202 wxScrollbarVisibility vert)
203 {
204 GtkScrolledWindow * const scrolled = GTK_SCROLLED_WINDOW(m_win->m_widget);
205 wxCHECK_RET( scrolled, "window must be created" );
206
207 gtk_scrolled_window_set_policy(scrolled,
208 GtkPolicyFromWX(horz),
209 GtkPolicyFromWX(vert));
210 }