#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)
{
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)
{
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());
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
{
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();
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: win->SetWindowStyleFlag(style | wxALWAYS_SHOW_SB);
win->SetScrollbar(wxHORIZONTAL, x, crect.width, vrect.width, refresh);
break;
}
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: 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
{
return nativeWindow() != NULL;
}
void ScrollView::wheelEvent(PlatformWheelEvent& e)
{
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);
}
}
void ScrollView::addChild(Widget* widget)
{
m_data->m_children.add(widget);
}
void ScrollView::removeChild(Widget* widget)
{
m_data->m_children.remove(widget);
if (nativeWindow() && widget->nativeWindow()) {
nativeWindow()->RemoveChild(widget->nativeWindow());
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)
{
return 0;
}
IntSize ScrollView::maximumScroll() const
{
IntSize delta = (IntSize(contentsWidth(), contentsHeight()) - IntSize(visibleWidth(), visibleHeight())) - scrollOffset();
delta.clampNegativeToZero();
return delta;
}
}