diff options
Diffstat (limited to 'WebCore/platform/wx/ScrollViewWx.cpp')
-rw-r--r-- | WebCore/platform/wx/ScrollViewWx.cpp | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/WebCore/platform/wx/ScrollViewWx.cpp b/WebCore/platform/wx/ScrollViewWx.cpp new file mode 100644 index 0000000..b6c5ae4 --- /dev/null +++ b/WebCore/platform/wx/ScrollViewWx.cpp @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollView.h" + +#include "FloatRect.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "PlatformWheelEvent.h" +#include "ScrollBar.h" + +#include <algorithm> +#include <stdio.h> + +#include <wx/defs.h> +#include <wx/scrolwin.h> +#include <wx/event.h> + +using namespace std; + +namespace WebCore { + +class ScrollView::ScrollViewPrivate : public wxEvtHandler { + +public: + ScrollViewPrivate(ScrollView* scrollView) + : wxEvtHandler() + , m_scrollView(scrollView) + , hasStaticBackground(false) + , suppressScrollbars(false) + , vScrollbarMode(ScrollbarAuto) + , hScrollbarMode(ScrollbarAuto) + , viewStart(0, 0) + { + } + + void bindEvents(wxWindow* win) + { + // TODO: is there an easier way to Connect to a range of events? these are contiguous. + win->Connect(wxEVT_SCROLLWIN_TOP, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this); + win->Connect(wxEVT_SCROLLWIN_BOTTOM, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this); + win->Connect(wxEVT_SCROLLWIN_LINEUP, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this); + win->Connect(wxEVT_SCROLLWIN_LINEDOWN, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this); + win->Connect(wxEVT_SCROLLWIN_PAGEUP, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this); + win->Connect(wxEVT_SCROLLWIN_PAGEDOWN, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this); + win->Connect(wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this); + win->Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this); + win->Connect(wxEVT_SCROLLWIN_TOP, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this); + } + + void OnScrollWinEvents(wxScrollWinEvent& e) + { + wxEventType scrollType(e.GetEventType()); + bool horiz = e.GetOrientation() == wxHORIZONTAL; + + wxPoint pos(viewStart); + + if (scrollType == wxEVT_SCROLLWIN_THUMBTRACK || scrollType == wxEVT_SCROLLWIN_THUMBRELEASE) { + if (horiz) + pos.x = e.GetPosition(); + else + pos.y = e.GetPosition(); + } + else if ( scrollType == wxEVT_SCROLLWIN_LINEDOWN ) { + if (horiz) + pos.x += LINE_STEP; + else + pos.y += LINE_STEP; + } + else if ( scrollType == wxEVT_SCROLLWIN_LINEUP ) { + if (horiz) + pos.x -= LINE_STEP; + else + pos.y -= LINE_STEP; + } + else + return e.Skip(); + + m_scrollView->setContentsPos(pos.x, pos.y); + m_scrollView->update(); + } + + ScrollView* m_scrollView; + + HashSet<Widget*> m_children; + bool hasStaticBackground; + bool suppressScrollbars; + ScrollbarMode vScrollbarMode; + ScrollbarMode hScrollbarMode; + wxPoint viewStart; +}; + +ScrollView::ScrollView() +{ + m_data = new ScrollViewPrivate(this); +} + +void ScrollView::setNativeWindow(wxWindow* win) +{ + Widget::setNativeWindow(win); + m_data->bindEvents(win); +} + +ScrollView::~ScrollView() +{ + delete m_data; +} + +void ScrollView::updateContents(const IntRect& updateRect, bool now) +{ + // we need to convert coordinates to scrolled position + wxRect contentsRect = updateRect; + contentsRect.Offset(-contentsX(), -contentsY()); + wxWindow* win = nativeWindow(); + if (win) { + win->RefreshRect(contentsRect, true); + if (now) + win->Update(); + } +} + +void ScrollView::update() +{ + wxWindow* win = nativeWindow(); + if (win) + win->Update(); +} + +int ScrollView::visibleWidth() const +{ + int width = 0; + wxWindow* win = nativeWindow(); + if (win) + win->GetClientSize(&width, NULL); + + ASSERT(width >= 0); + return width; +} + +int ScrollView::visibleHeight() const +{ + int height = 0; + wxWindow* win = nativeWindow(); + if (win) + win->GetClientSize(NULL, &height); + + ASSERT(height >= 0); + return height; +} + +FloatRect ScrollView::visibleContentRect() const +{ + return FloatRect(contentsX(),contentsY(),visibleWidth(),visibleHeight()); +} + +void ScrollView::setContentsPos(int newX, int newY) +{ + int dx = newX - contentsX(); + int dy = newY - contentsY(); + scrollBy(dx, dy); +} + +void ScrollView::scrollBy(int dx, int dy) +{ + wxWindow* win = nativeWindow(); + if (!win) + return; + + wxPoint scrollOffset = m_data->viewStart; + wxPoint orig(scrollOffset); + wxPoint newScrollOffset = scrollOffset + wxPoint(dx, dy); + + wxRect vRect(win->GetVirtualSize()); + wxRect cRect(win->GetClientSize()); + + // clamp to scroll area + if (newScrollOffset.x < 0) + newScrollOffset.x = 0; + else if (newScrollOffset.x + cRect.width > vRect.width) + newScrollOffset.x = max(0, vRect.width - cRect.width - 1); + + if (newScrollOffset.y < 0) + newScrollOffset.y = 0; + else if (newScrollOffset.y + cRect.height > vRect.height) + newScrollOffset.y = max(0, vRect.height - cRect.height - 1); + + if (newScrollOffset == scrollOffset) + return; + + m_data->viewStart = newScrollOffset; + + wxPoint delta(orig - newScrollOffset); + + if (m_data->hasStaticBackground) + win->Refresh(); + else + win->ScrollWindow(delta.x, delta.y); + + adjustScrollbars(); +} + +void ScrollView::resizeContents(int w,int h) +{ + wxWindow* win = nativeWindow(); + if (win) { + win->SetVirtualSize(w, h); + adjustScrollbars(); + } +} + +int ScrollView::contentsX() const +{ + ASSERT(m_data->viewStart.x >= 0); + return m_data->viewStart.x; +} + +int ScrollView::contentsY() const +{ + ASSERT(m_data->viewStart.y >= 0); + return m_data->viewStart.y; +} + +int ScrollView::contentsWidth() const +{ + int width = 0; + wxWindow* win = nativeWindow(); + if (win) + win->GetVirtualSize(&width, NULL); + ASSERT(width >= 0); + return width; +} + +int ScrollView::contentsHeight() const +{ + int height = 0; + wxWindow* win = nativeWindow(); + if (win) + win->GetVirtualSize(NULL, &height); + ASSERT(height >= 0); + return height; +} + +FloatRect ScrollView::visibleContentRectConsideringExternalScrollers() const +{ + // FIXME: clip this rect if parent scroll views cut off the visible + // area. + return visibleContentRect(); +} + +IntSize ScrollView::scrollOffset() const +{ + return IntSize(contentsX(), contentsY()); +} + +void ScrollView::adjustScrollbars(int x, int y, bool refresh) +{ + wxWindow* win = nativeWindow(); + if (!win) + return; + + wxRect crect(win->GetClientRect()), vrect(win->GetVirtualSize()); + + if (x == -1) x = m_data->viewStart.x; + if (y == -1) y = m_data->viewStart.y; + + long style = win->GetWindowStyle(); + + // by setting the wxALWAYS_SHOW_SB wxWindow flag before + // each SetScrollbar call, we can control the scrollbars + // visibility individually. + + // horizontal scrollbar + switch (m_data->hScrollbarMode) { + case ScrollbarAlwaysOff: + win->SetWindowStyleFlag(style & ~wxALWAYS_SHOW_SB); + win->SetScrollbar(wxHORIZONTAL, 0, 0, 0, refresh); + break; + + case ScrollbarAuto: + win->SetWindowStyleFlag(style & ~wxALWAYS_SHOW_SB); + win->SetScrollbar(wxHORIZONTAL, x, crect.width, vrect.width, refresh); + break; + + default: // ScrollbarAlwaysOn + win->SetWindowStyleFlag(style | wxALWAYS_SHOW_SB); + win->SetScrollbar(wxHORIZONTAL, x, crect.width, vrect.width, refresh); + break; + } + + // vertical scrollbar + switch (m_data->vScrollbarMode) { + case ScrollbarAlwaysOff: + win->SetWindowStyleFlag(style & ~wxALWAYS_SHOW_SB); + win->SetScrollbar(wxVERTICAL, 0, 0, 0, refresh); + break; + + case ScrollbarAlwaysOn: + win->SetWindowStyleFlag(style | wxALWAYS_SHOW_SB); + win->SetScrollbar(wxVERTICAL, y, crect.height, vrect.height, refresh); + break; + + default: // case ScrollbarAuto: + win->SetWindowStyleFlag(style & ~wxALWAYS_SHOW_SB); + win->SetScrollbar(wxVERTICAL, y, crect.height, vrect.height, refresh); + } +} + +WebCore::ScrollbarMode ScrollView::hScrollbarMode() const +{ + return m_data->hScrollbarMode; +} + +WebCore::ScrollbarMode ScrollView::vScrollbarMode() const +{ + return m_data->vScrollbarMode; +} + +void ScrollView::setScrollbarsMode(ScrollbarMode newMode) +{ + bool needsAdjust = false; + + if (m_data->hScrollbarMode != newMode) { + m_data->hScrollbarMode = newMode; + needsAdjust = true; + } + + if (m_data->vScrollbarMode != newMode) { + m_data->vScrollbarMode = newMode; + adjustScrollbars(); + needsAdjust = true; + } + + if (needsAdjust) + adjustScrollbars(); +} + +void ScrollView::setHScrollbarMode(ScrollbarMode newMode) +{ + if (m_data->hScrollbarMode != newMode) { + m_data->hScrollbarMode = newMode; + adjustScrollbars(); + } +} + +void ScrollView::setVScrollbarMode(ScrollbarMode newMode) +{ + if (m_data->vScrollbarMode != newMode) { + m_data->vScrollbarMode = newMode; + adjustScrollbars(); + } +} + +void ScrollView::setStaticBackground(bool flag) +{ + m_data->hasStaticBackground = flag; +} + +void ScrollView::suppressScrollbars(bool suppressed, bool repaintOnSuppress) +{ + if ( m_data->suppressScrollbars != suppressed ) + m_data->suppressScrollbars = suppressed; +} + +IntPoint ScrollView::contentsToWindow(const IntPoint& point) const +{ + return point - scrollOffset(); +} + +IntPoint ScrollView::windowToContents(const IntPoint& point) const +{ + return point + scrollOffset(); +} + +bool ScrollView::inWindow() const +{ + // NB: This is called from RenderObject::willRenderImage + // and really seems to be more of a "is the window in a valid state" test, + // despite the API name. + return nativeWindow() != NULL; +} + +void ScrollView::wheelEvent(PlatformWheelEvent& e) +{ + // Determine how much we want to scroll. If we can move at all, we will accept the event. + IntSize maxScrollDelta = maximumScroll(); + if ((e.deltaX() < 0 && maxScrollDelta.width() > 0) || + (e.deltaX() > 0 && scrollOffset().width() > 0) || + (e.deltaY() < 0 && maxScrollDelta.height() > 0) || + (e.deltaY() > 0 && scrollOffset().height() > 0)) { + e.accept(); + scrollBy(-e.deltaX() * LINE_STEP, -e.deltaY() * LINE_STEP); + } +} + +// used for subframes support +void ScrollView::addChild(Widget* widget) +{ + m_data->m_children.add(widget); + + // NB: In all cases I'm aware of, + // by the time this is called the ScrollView is already a child + // of its parent Widget by wx port APIs, so I don't think + // we need to do anything here. +} + +void ScrollView::removeChild(Widget* widget) +{ + m_data->m_children.remove(widget); + + if (nativeWindow() && widget->nativeWindow()) { + nativeWindow()->RemoveChild(widget->nativeWindow()); + // FIXME: Is this the right place to do deletion? I see + // detachFromParent2/3/4, initiated by FrameLoader::detachFromParent, + // but I'm not sure if it's better to handle there or not. + widget->nativeWindow()->Destroy(); + } +} + +HashSet<Widget*>* ScrollView::children() +{ + return &(m_data->m_children); +} + +void ScrollView::scrollRectIntoViewRecursively(const IntRect& rect) +{ + setContentsPos(rect.x(), rect.y()); +} + +PlatformScrollbar* ScrollView::scrollbarUnderMouse(const PlatformMouseEvent& mouseEvent) +{ + // AFAICT this is only used for platforms that provide + // feedback when mouse is hovered over. + return 0; +} + +IntSize ScrollView::maximumScroll() const +{ + IntSize delta = (IntSize(contentsWidth(), contentsHeight()) - IntSize(visibleWidth(), visibleHeight())) - scrollOffset(); + delta.clampNegativeToZero(); + return delta; +} + +} |