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