• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "ScrollView.h"
28 
29 #include "FloatRect.h"
30 #include "IntRect.h"
31 #include "NotImplemented.h"
32 #include "PlatformWheelEvent.h"
33 #include "Scrollbar.h"
34 
35 #include <algorithm>
36 #include <stdio.h>
37 
38 #include <wx/defs.h>
39 #include <wx/scrolbar.h>
40 #include <wx/scrolwin.h>
41 #include <wx/event.h>
42 
43 using namespace std;
44 
45 namespace WebCore {
46 
47 class ScrollView::ScrollViewPrivate : public wxEvtHandler {
48 
49 public:
ScrollViewPrivate(ScrollView * scrollView)50     ScrollViewPrivate(ScrollView* scrollView)
51         : wxEvtHandler()
52         , m_scrollView(scrollView)
53         , vScrollbarMode(ScrollbarAuto)
54         , hScrollbarMode(ScrollbarAuto)
55         , viewStart(0, 0)
56     {
57     }
58 
bindEvents(wxWindow * win)59     void bindEvents(wxWindow* win)
60     {
61         // TODO: is there an easier way to Connect to a range of events? these are contiguous.
62         win->Connect(wxEVT_SCROLLWIN_TOP,          wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
63         win->Connect(wxEVT_SCROLLWIN_BOTTOM,       wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
64         win->Connect(wxEVT_SCROLLWIN_LINEUP,       wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
65         win->Connect(wxEVT_SCROLLWIN_LINEDOWN,     wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
66         win->Connect(wxEVT_SCROLLWIN_PAGEUP,       wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
67         win->Connect(wxEVT_SCROLLWIN_PAGEDOWN,     wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
68         win->Connect(wxEVT_SCROLLWIN_THUMBTRACK,   wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
69         win->Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
70     }
71 
OnScrollWinEvents(wxScrollWinEvent & e)72     void OnScrollWinEvents(wxScrollWinEvent& e)
73     {
74         wxEventType scrollType(e.GetEventType());
75         bool horiz = e.GetOrientation() == wxHORIZONTAL;
76 
77         wxPoint pos(viewStart);
78 
79         if (scrollType == wxEVT_SCROLLWIN_THUMBTRACK || scrollType == wxEVT_SCROLLWIN_THUMBRELEASE) {
80             if (horiz)
81                 pos.x = e.GetPosition();
82             else
83                 pos.y = e.GetPosition();
84         }
85         else if (scrollType == wxEVT_SCROLLWIN_LINEDOWN) {
86             if (horiz)
87                 pos.x += Scrollbar::pixelsPerLineStep();
88             else
89                 pos.y += Scrollbar::pixelsPerLineStep();
90         }
91         else if (scrollType == wxEVT_SCROLLWIN_LINEUP) {
92             if (horiz)
93                 pos.x -= Scrollbar::pixelsPerLineStep();
94             else
95                 pos.y -= Scrollbar::pixelsPerLineStep();
96         }
97         else if (scrollType == wxEVT_SCROLLWIN_PAGEUP) {
98             if (horiz)
99                 pos.x -= max<int>(m_scrollView->visibleWidth() * Scrollbar::minFractionToStepWhenPaging(), m_scrollView->visibleWidth() - Scrollbar::maxOverlapBetweenPages());
100             else
101                 pos.y -= max<int>(m_scrollView->visibleHeight() * Scrollbar::minFractionToStepWhenPaging(), m_scrollView->visibleHeight() - Scrollbar::maxOverlapBetweenPages());
102         }
103         else if (scrollType == wxEVT_SCROLLWIN_PAGEDOWN) {
104             if (horiz)
105                 pos.x += max<int>(m_scrollView->visibleWidth() * Scrollbar::minFractionToStepWhenPaging(), m_scrollView->visibleWidth() - Scrollbar::maxOverlapBetweenPages());
106             else
107                 pos.y += max<int>(m_scrollView->visibleHeight() * Scrollbar::minFractionToStepWhenPaging(), m_scrollView->visibleHeight() - Scrollbar::maxOverlapBetweenPages());
108         }
109         else
110             return e.Skip();
111 
112         m_scrollView->setScrollPosition(IntPoint(pos.x, pos.y));
113     }
114 
115     ScrollView* m_scrollView;
116 
117     ScrollbarMode vScrollbarMode;
118     ScrollbarMode hScrollbarMode;
119     wxPoint viewStart;
120 };
121 
platformInit()122 void ScrollView::platformInit()
123 {
124     m_data = new ScrollViewPrivate(this);
125 }
126 
127 
platformDestroy()128 void ScrollView::platformDestroy()
129 {
130     delete m_data;
131 }
132 
setPlatformWidget(wxWindow * win)133 void ScrollView::setPlatformWidget(wxWindow* win)
134 {
135     Widget::setPlatformWidget(win);
136     m_data->bindEvents(win);
137 }
138 
platformRepaintContentRectangle(const IntRect & updateRect,bool now)139 void ScrollView::platformRepaintContentRectangle(const IntRect& updateRect, bool now)
140 {
141     // we need to convert coordinates to scrolled position
142     wxRect contentsRect = updateRect;
143     contentsRect.Offset(-scrollX(), -scrollY());
144     wxWindow* win = platformWidget();
145     if (win) {
146         win->RefreshRect(contentsRect, true);
147         if (now)
148             win->Update();
149     }
150 }
151 
platformVisibleContentRect(bool includeScrollbars) const152 IntRect ScrollView::platformVisibleContentRect(bool includeScrollbars) const
153 {
154     wxWindow* win = platformWidget();
155     if (!win)
156         return IntRect();
157 
158     int width, height;
159 
160     if (includeScrollbars)
161         win->GetSize(&width, &height);
162     else
163         win->GetClientSize(&width, &height);
164 
165     return IntRect(m_data->viewStart.x, m_data->viewStart.y, width, height);
166 }
167 
platformContentsSize() const168 IntSize ScrollView::platformContentsSize() const
169 {
170     int width = 0;
171     int height = 0;
172     if (platformWidget()) {
173         platformWidget()->GetVirtualSize(&width, &height);
174         ASSERT(width >= 0 && height >= 0);
175     }
176     return IntSize(width, height);
177 }
178 
platformSetScrollPosition(const IntPoint & scrollPoint)179 void ScrollView::platformSetScrollPosition(const IntPoint& scrollPoint)
180 {
181     wxWindow* win = platformWidget();
182 
183     wxPoint scrollOffset = m_data->viewStart;
184     wxPoint orig(scrollOffset);
185     wxPoint newScrollOffset(scrollPoint);
186 
187     wxRect vRect(win->GetVirtualSize());
188     wxRect cRect(win->GetClientSize());
189 
190     // clamp to scroll area
191     if (newScrollOffset.x < 0)
192         newScrollOffset.x = 0;
193     else if (newScrollOffset.x + cRect.width > vRect.width)
194         newScrollOffset.x = max(0, vRect.width - cRect.width);
195 
196     if (newScrollOffset.y < 0)
197         newScrollOffset.y = 0;
198     else if (newScrollOffset.y + cRect.height > vRect.height)
199         newScrollOffset.y = max(0, vRect.height - cRect.height);
200 
201     if (newScrollOffset == scrollOffset)
202         return;
203 
204     m_data->viewStart = newScrollOffset;
205 
206     wxPoint delta(orig - newScrollOffset);
207 
208     if (canBlitOnScroll())
209         win->ScrollWindow(delta.x, delta.y);
210     else
211         win->Refresh();
212 
213     adjustScrollbars();
214 }
215 
platformScroll(ScrollDirection,ScrollGranularity)216 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
217 {
218     notImplemented();
219     return true;
220 }
221 
platformSetContentsSize()222 void ScrollView::platformSetContentsSize()
223 {
224     wxWindow* win = platformWidget();
225     if (!win)
226         return;
227 
228     win->SetVirtualSize(m_contentsSize.width(), m_contentsSize.height());
229     adjustScrollbars();
230 }
231 
adjustScrollbars(int x,int y,bool refresh)232 void ScrollView::adjustScrollbars(int x, int y, bool refresh)
233 {
234     wxWindow* win = platformWidget();
235     if (!win)
236         return;
237 
238     wxRect crect(win->GetClientRect()), vrect(win->GetVirtualSize());
239 
240     if (x == -1) x = m_data->viewStart.x;
241     if (y == -1) y = m_data->viewStart.y;
242 
243     long style = win->GetWindowStyle();
244 
245     // by setting the wxALWAYS_SHOW_SB wxWindow flag before
246     // each SetScrollbar call, we can control the scrollbars
247     // visibility individually.
248 
249     // horizontal scrollbar
250     switch (m_data->hScrollbarMode) {
251         case ScrollbarAlwaysOff:
252             win->SetWindowStyleFlag(style & ~wxALWAYS_SHOW_SB);
253             win->SetScrollbar(wxHORIZONTAL, 0, 0, 0, refresh);
254             break;
255 
256         case ScrollbarAuto:
257             win->SetWindowStyleFlag(style & ~wxALWAYS_SHOW_SB);
258             win->SetScrollbar(wxHORIZONTAL, x, crect.width, vrect.width, refresh);
259             break;
260 
261         default: // ScrollbarAlwaysOn
262             win->SetWindowStyleFlag(style | wxALWAYS_SHOW_SB);
263             win->SetScrollbar(wxHORIZONTAL, x, crect.width, vrect.width, refresh);
264             break;
265     }
266 
267     // vertical scrollbar
268     switch (m_data->vScrollbarMode) {
269         case ScrollbarAlwaysOff:
270             win->SetWindowStyleFlag(style & ~wxALWAYS_SHOW_SB);
271             win->SetScrollbar(wxVERTICAL, 0, 0, 0, refresh);
272             break;
273 
274         case ScrollbarAlwaysOn:
275             win->SetWindowStyleFlag(style | wxALWAYS_SHOW_SB);
276             win->SetScrollbar(wxVERTICAL, y, crect.height, vrect.height, refresh);
277             break;
278 
279         default: // case ScrollbarAuto:
280             win->SetWindowStyleFlag(style & ~wxALWAYS_SHOW_SB);
281             win->SetScrollbar(wxVERTICAL, y, crect.height, vrect.height, refresh);
282     }
283 }
284 
platformSetScrollbarModes()285 void ScrollView::platformSetScrollbarModes()
286 {
287     bool needsAdjust = false;
288 
289     if (m_data->hScrollbarMode != horizontalScrollbarMode() ) {
290         m_data->hScrollbarMode = horizontalScrollbarMode();
291         needsAdjust = true;
292     }
293 
294     if (m_data->vScrollbarMode != verticalScrollbarMode() ) {
295         m_data->vScrollbarMode = verticalScrollbarMode();
296         needsAdjust = true;
297     }
298 
299     if (needsAdjust)
300         adjustScrollbars();
301 }
302 
platformScrollbarModes(ScrollbarMode & horizontal,ScrollbarMode & vertical) const303 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
304 {
305     horizontal = m_data->hScrollbarMode;
306     vertical = m_data->vScrollbarMode;
307 }
308 
platformSetCanBlitOnScroll(bool canBlitOnScroll)309 void ScrollView::platformSetCanBlitOnScroll(bool canBlitOnScroll)
310 {
311     m_canBlitOnScroll = canBlitOnScroll;
312 }
313 
platformCanBlitOnScroll() const314 bool ScrollView::platformCanBlitOnScroll() const
315 {
316     return m_canBlitOnScroll;
317 }
318 
319 // used for subframes support
platformAddChild(Widget * widget)320 void ScrollView::platformAddChild(Widget* widget)
321 {
322     // NB: In all cases I'm aware of,
323     // by the time this is called the ScrollView is already a child
324     // of its parent Widget by wx port APIs, so I don't think
325     // we need to do anything here.
326 }
327 
platformRemoveChild(Widget * widget)328 void ScrollView::platformRemoveChild(Widget* widget)
329 {
330     if (platformWidget()) {
331         platformWidget()->RemoveChild(widget->platformWidget());
332         // FIXME: Is this the right place to do deletion? I see
333         // detachFromParent2/3/4, initiated by FrameLoader::detachFromParent,
334         // but I'm not sure if it's better to handle there or not.
335         widget->platformWidget()->Destroy();
336     }
337 }
338 
platformContentsToScreen(const IntRect & rect) const339 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
340 {
341     if (platformWidget()) {
342         wxRect wxrect = rect;
343         platformWidget()->ClientToScreen(&wxrect.x, &wxrect.y);
344         return wxrect;
345     }
346     return IntRect();
347 }
348 
platformScreenToContents(const IntPoint & point) const349 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
350 {
351     if (platformWidget()) {
352         return platformWidget()->ScreenToClient(point);
353     }
354     return IntPoint();
355 }
356 
platformIsOffscreen() const357 bool ScrollView::platformIsOffscreen() const
358 {
359     return !platformWidget() || !platformWidget()->IsShownOnScreen();
360 }
361 
362 }
363