Commit 13f02f88 authored by pkasting@chromium.org's avatar pkasting@chromium.org

2009-04-16 Peter Kasting <pkasting@google.com>

        Reviewed by David Hyatt.

        https://bugs.webkit.org/show_bug.cgi?id=25250
        Allow platforms to snap the scroll thumb back to the drag origin
        during a drag.  Implement functions for Safari/Win and Chromium/Win
        to do this snapping at distances approximating the native ones.

        * platform/Scrollbar.cpp:
        (WebCore::Scrollbar::Scrollbar):
        (WebCore::Scrollbar::setValue):
        (WebCore::Scrollbar::scroll):
        (WebCore::Scrollbar::moveThumb):
        (WebCore::Scrollbar::setCurrentPos):
        (WebCore::Scrollbar::mouseMoved):
        (WebCore::Scrollbar::mouseDown):
        * platform/Scrollbar.h:
        * platform/ScrollbarTheme.h:
        (WebCore::ScrollbarTheme::shouldSnapBackToDragOrigin):
        * platform/chromium/ScrollbarThemeChromium.h:
        * platform/chromium/ScrollbarThemeChromiumLinux.cpp:
        (WebCore::ScrollbarThemeChromium::shouldSnapBackToDragOrigin):
        * platform/chromium/ScrollbarThemeChromiumWin.cpp:
        (WebCore::ScrollbarThemeChromium::shouldSnapBackToDragOrigin):
        * platform/win/ScrollbarThemeWin.cpp:
        (WebCore::ScrollbarThemeWin::shouldCenterOnThumb):
        (WebCore::ScrollbarThemeWin::shouldSnapBackToDragOrigin):
        * platform/win/ScrollbarThemeWin.h:



git-svn-id: svn://svn.chromium.org/blink/trunk@42721 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent a791ab1c
2009-04-16 Peter Kasting <pkasting@google.com>
Reviewed by David Hyatt.
https://bugs.webkit.org/show_bug.cgi?id=25250
Allow platforms to snap the scroll thumb back to the drag origin
during a drag. Implement functions for Safari/Win and Chromium/Win
to do this snapping at distances approximating the native ones.
* platform/Scrollbar.cpp:
(WebCore::Scrollbar::Scrollbar):
(WebCore::Scrollbar::setValue):
(WebCore::Scrollbar::scroll):
(WebCore::Scrollbar::moveThumb):
(WebCore::Scrollbar::setCurrentPos):
(WebCore::Scrollbar::mouseMoved):
(WebCore::Scrollbar::mouseDown):
* platform/Scrollbar.h:
* platform/ScrollbarTheme.h:
(WebCore::ScrollbarTheme::shouldSnapBackToDragOrigin):
* platform/chromium/ScrollbarThemeChromium.h:
* platform/chromium/ScrollbarThemeChromiumLinux.cpp:
(WebCore::ScrollbarThemeChromium::shouldSnapBackToDragOrigin):
* platform/chromium/ScrollbarThemeChromiumWin.cpp:
(WebCore::ScrollbarThemeChromium::shouldSnapBackToDragOrigin):
* platform/win/ScrollbarThemeWin.cpp:
(WebCore::ScrollbarThemeWin::shouldCenterOnThumb):
(WebCore::ScrollbarThemeWin::shouldSnapBackToDragOrigin):
* platform/win/ScrollbarThemeWin.h:
2009-04-21 Adam Roben <aroben@apple.com> 2009-04-21 Adam Roben <aroben@apple.com>
Windows build fix Windows build fix
...@@ -57,6 +57,7 @@ Scrollbar::Scrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ...@@ -57,6 +57,7 @@ Scrollbar::Scrollbar(ScrollbarClient* client, ScrollbarOrientation orientation,
, m_visibleSize(0) , m_visibleSize(0)
, m_totalSize(0) , m_totalSize(0)
, m_currentPos(0) , m_currentPos(0)
, m_dragOrigin(0)
, m_lineStep(0) , m_lineStep(0)
, m_pageStep(0) , m_pageStep(0)
, m_pixelStep(1) , m_pixelStep(1)
...@@ -92,13 +93,7 @@ bool Scrollbar::setValue(int v) ...@@ -92,13 +93,7 @@ bool Scrollbar::setValue(int v)
v = max(min(v, m_totalSize - m_visibleSize), 0); v = max(min(v, m_totalSize - m_visibleSize), 0);
if (value() == v) if (value() == v)
return false; // Our value stayed the same. return false; // Our value stayed the same.
m_currentPos = v; setCurrentPos(v);
updateThumbPosition();
if (client())
client()->valueChanged(this);
return true; return true;
} }
...@@ -139,20 +134,7 @@ bool Scrollbar::scroll(ScrollDirection direction, ScrollGranularity granularity, ...@@ -139,20 +134,7 @@ bool Scrollbar::scroll(ScrollDirection direction, ScrollGranularity granularity,
float newPos = m_currentPos + step * multiplier; float newPos = m_currentPos + step * multiplier;
float maxPos = m_totalSize - m_visibleSize; float maxPos = m_totalSize - m_visibleSize;
newPos = max(min(newPos, maxPos), 0.0f); return setCurrentPos(max(min(newPos, maxPos), 0.0f));
if (newPos == m_currentPos)
return false;
int oldValue = value();
m_currentPos = newPos;
updateThumbPosition();
if (value() != oldValue && client())
client()->valueChanged(this);
// return true even if the integer value did not change so that scroll event gets eaten
return true;
} }
void Scrollbar::updateThumbPosition() void Scrollbar::updateThumbPosition()
...@@ -269,15 +251,30 @@ void Scrollbar::moveThumb(int pos) ...@@ -269,15 +251,30 @@ void Scrollbar::moveThumb(int pos)
int thumbLen = theme()->thumbLength(this); int thumbLen = theme()->thumbLength(this);
int trackLen = theme()->trackLength(this); int trackLen = theme()->trackLength(this);
int maxPos = trackLen - thumbLen; int maxPos = trackLen - thumbLen;
int delta = pos - pressedPos(); int delta = pos - m_pressedPos;
if (delta > 0) if (delta > 0)
delta = min(maxPos - thumbPos, delta); delta = min(maxPos - thumbPos, delta);
else if (delta < 0) else if (delta < 0)
delta = max(-thumbPos, delta); delta = max(-thumbPos, delta);
if (delta) { if (delta)
setValue(static_cast<int>(static_cast<float>(thumbPos + delta) * maximum() / (trackLen - thumbLen))); setCurrentPos(static_cast<float>(thumbPos + delta) * maximum() / (trackLen - thumbLen));
setPressedPos(pressedPos() + theme()->thumbPosition(this) - thumbPos); }
}
bool Scrollbar::setCurrentPos(float pos)
{
if (pos == m_currentPos)
return false;
int oldValue = value();
int oldThumbPos = theme()->thumbPosition(this);
m_currentPos = pos;
updateThumbPosition();
if (m_pressedPart == ThumbPart)
setPressedPos(m_pressedPos + theme()->thumbPosition(this) - oldThumbPos);
if (value() != oldValue && client())
client()->valueChanged(this);
return true;
} }
void Scrollbar::setHoveredPart(ScrollbarPart part) void Scrollbar::setHoveredPart(ScrollbarPart part)
...@@ -308,9 +305,13 @@ void Scrollbar::setPressedPart(ScrollbarPart part) ...@@ -308,9 +305,13 @@ void Scrollbar::setPressedPart(ScrollbarPart part)
bool Scrollbar::mouseMoved(const PlatformMouseEvent& evt) bool Scrollbar::mouseMoved(const PlatformMouseEvent& evt)
{ {
if (m_pressedPart == ThumbPart) { if (m_pressedPart == ThumbPart) {
moveThumb(m_orientation == HorizontalScrollbar ? if (theme()->shouldSnapBackToDragOrigin(this, evt))
convertFromContainingWindow(evt.pos()).x() : setCurrentPos(m_dragOrigin);
convertFromContainingWindow(evt.pos()).y()); else {
moveThumb(m_orientation == HorizontalScrollbar ?
convertFromContainingWindow(evt.pos()).x() :
convertFromContainingWindow(evt.pos()).y());
}
return true; return true;
} }
...@@ -366,9 +367,10 @@ bool Scrollbar::mouseDown(const PlatformMouseEvent& evt) ...@@ -366,9 +367,10 @@ bool Scrollbar::mouseDown(const PlatformMouseEvent& evt)
setPressedPart(theme()->hitTest(this, evt)); setPressedPart(theme()->hitTest(this, evt));
int pressedPos = (orientation() == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y()); int pressedPos = (orientation() == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
if ((pressedPart() == BackTrackPart || pressedPart() == ForwardTrackPart) && theme()->shouldCenterOnThumb(this, evt)) { if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && theme()->shouldCenterOnThumb(this, evt)) {
setHoveredPart(ThumbPart); setHoveredPart(ThumbPart);
setPressedPart(ThumbPart); setPressedPart(ThumbPart);
m_dragOrigin = m_currentPos;
int thumbLen = theme()->thumbLength(this); int thumbLen = theme()->thumbLength(this);
int desiredPos = pressedPos; int desiredPos = pressedPos;
// Set the pressed position to the middle of the thumb so that when we do the move, the delta // Set the pressed position to the middle of the thumb so that when we do the move, the delta
...@@ -376,7 +378,8 @@ bool Scrollbar::mouseDown(const PlatformMouseEvent& evt) ...@@ -376,7 +378,8 @@ bool Scrollbar::mouseDown(const PlatformMouseEvent& evt)
m_pressedPos = theme()->trackPosition(this) + theme()->thumbPosition(this) + thumbLen / 2; m_pressedPos = theme()->trackPosition(this) + theme()->thumbPosition(this) + thumbLen / 2;
moveThumb(desiredPos); moveThumb(desiredPos);
return true; return true;
} } else if (m_pressedPart == ThumbPart)
m_dragOrigin = m_currentPos;
m_pressedPos = pressedPos; m_pressedPos = pressedPos;
......
...@@ -137,6 +137,7 @@ protected: ...@@ -137,6 +137,7 @@ protected:
ScrollGranularity pressedPartScrollGranularity(); ScrollGranularity pressedPartScrollGranularity();
void moveThumb(int pos); void moveThumb(int pos);
bool setCurrentPos(float pos);
ScrollbarClient* m_client; ScrollbarClient* m_client;
ScrollbarOrientation m_orientation; ScrollbarOrientation m_orientation;
...@@ -146,6 +147,7 @@ protected: ...@@ -146,6 +147,7 @@ protected:
int m_visibleSize; int m_visibleSize;
int m_totalSize; int m_totalSize;
float m_currentPos; float m_currentPos;
float m_dragOrigin;
int m_lineStep; int m_lineStep;
int m_pageStep; int m_pageStep;
float m_pixelStep; float m_pixelStep;
......
...@@ -76,6 +76,7 @@ public: ...@@ -76,6 +76,7 @@ public:
virtual void paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect) { context->fillRect(cornerRect, Color::white); } virtual void paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect) { context->fillRect(cornerRect, Color::white); }
virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&) { return false; } virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&) { return false; }
virtual bool shouldSnapBackToDragOrigin(Scrollbar*, const PlatformMouseEvent&) { return false; }
virtual int thumbPosition(Scrollbar*) { return 0; } // The position of the thumb relative to the track. virtual int thumbPosition(Scrollbar*) { return 0; } // The position of the thumb relative to the track.
virtual int thumbLength(Scrollbar*) { return 0; } // The length of the thumb along the axis of the scrollbar. virtual int thumbLength(Scrollbar*) { return 0; } // The length of the thumb along the axis of the scrollbar.
virtual int trackPosition(Scrollbar*) { return 0; } // The position of the track relative to the scrollbar. virtual int trackPosition(Scrollbar*) { return 0; } // The position of the track relative to the scrollbar.
......
...@@ -63,6 +63,7 @@ namespace WebCore { ...@@ -63,6 +63,7 @@ namespace WebCore {
virtual void paintScrollCorner(ScrollView*, GraphicsContext*, const IntRect&); virtual void paintScrollCorner(ScrollView*, GraphicsContext*, const IntRect&);
virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&); virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&);
virtual bool shouldSnapBackToDragOrigin(Scrollbar*, const PlatformMouseEvent&);
virtual void paintTrackBackground(GraphicsContext*, Scrollbar*, const IntRect&); virtual void paintTrackBackground(GraphicsContext*, Scrollbar*, const IntRect&);
virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart);
......
...@@ -72,6 +72,11 @@ static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint) ...@@ -72,6 +72,11 @@ static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint)
drawVertLine(canvas, rect.x(), rect.y(), bottom, paint); drawVertLine(canvas, rect.x(), rect.y(), bottom, paint);
} }
bool ScrollbarThemeChromium::shouldSnapBackToDragOrigin(Scrollbar*, const PlatformMouseEvent&)
{
return false;
}
void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar,
const IntRect& rect, ScrollbarPart partType) const IntRect& rect, ScrollbarPart partType)
{ {
......
...@@ -44,6 +44,13 @@ namespace WebCore { ...@@ -44,6 +44,13 @@ namespace WebCore {
// Metrics obtained using [NSScroller scrollerWidthForControlSize:] // Metrics obtained using [NSScroller scrollerWidthForControlSize:]
static const int kMacScrollbarSize[3] = { 15, 11, 15 }; static const int kMacScrollbarSize[3] = { 15, 11, 15 };
// Constants used to figure the drag rect outside which we should snap the
// scrollbar thumb back to its origin. These calculations are based on
// observing the behavior of the MSVC8 main window scrollbar + some
// guessing/extrapolation.
static const int kOffEndMultiplier = 3;
static const int kOffSideMultiplier = 8;
int ScrollbarThemeChromium::scrollbarThickness(ScrollbarControlSize controlSize) int ScrollbarThemeChromium::scrollbarThickness(ScrollbarControlSize controlSize)
{ {
static int thickness; static int thickness;
...@@ -60,6 +67,24 @@ bool ScrollbarThemeChromium::invalidateOnMouseEnterExit() ...@@ -60,6 +67,24 @@ bool ScrollbarThemeChromium::invalidateOnMouseEnterExit()
return isVistaOrNewer(); return isVistaOrNewer();
} }
bool ScrollbarThemeChromium::shouldSnapBackToDragOrigin(Scrollbar* scrollbar, const PlatformMouseEvent& evt)
{
// Find the rect within which we shouldn't snap, by expanding the track rect
// in both dimensions.
IntRect rect = trackRect(scrollbar);
const bool horz = scrollbar->orientation() == HorizontalScrollbar;
const int thickness = scrollbarThickness(scrollbar->controlSize());
rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness);
rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness);
// Convert the event to local coordinates.
IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos());
mousePosition.move(scrollbar->x(), scrollbar->y());
// We should snap iff the event is outside our calculated rect.
return !rect.contains(mousePosition);
}
void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart partType) void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart partType)
{ {
bool horz = scrollbar->orientation() == HorizontalScrollbar; bool horz = scrollbar->orientation() == HorizontalScrollbar;
......
...@@ -72,6 +72,13 @@ SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc ...@@ -72,6 +72,13 @@ SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc
SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ()) SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ())
SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId)) SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))
// Constants used to figure the drag rect outside which we should snap the
// scrollbar thumb back to its origin. These calculations are based on
// observing the behavior of the MSVC8 main window scrollbar + some
// guessing/extrapolation.
static const int kOffEndMultiplier = 3;
static const int kOffSideMultiplier = 8;
static void checkAndInitScrollbarTheme() static void checkAndInitScrollbarTheme()
{ {
if (uxthemeLibrary() && !scrollbarTheme && IsThemeActive()) if (uxthemeLibrary() && !scrollbarTheme && IsThemeActive())
...@@ -180,6 +187,29 @@ IntRect ScrollbarThemeWin::trackRect(Scrollbar* scrollbar, bool) ...@@ -180,6 +187,29 @@ IntRect ScrollbarThemeWin::trackRect(Scrollbar* scrollbar, bool)
return IntRect(scrollbar->x(), scrollbar->y() + thickness, thickness, scrollbar->height() - 2 * thickness); return IntRect(scrollbar->x(), scrollbar->y() + thickness, thickness, scrollbar->height() - 2 * thickness);
} }
bool ScrollbarThemeWin::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
{
return evt.shiftKey() && evt.button() == LeftButton;
}
bool ScrollbarThemeWin::shouldSnapBackToDragOrigin(Scrollbar* scrollbar, const PlatformMouseEvent& evt)
{
// Find the rect within which we shouldn't snap, by expanding the track rect
// in both dimensions.
IntRect rect = trackRect(scrollbar);
const bool horz = scrollbar->orientation() == HorizontalScrollbar;
const int thickness = scrollbarThickness(scrollbar->controlSize());
rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness);
rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness);
// Convert the event to local coordinates.
IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos());
mousePosition.move(scrollbar->x(), scrollbar->y());
// We should snap iff the event is outside our calculated rect.
return !rect.contains(mousePosition);
}
void ScrollbarThemeWin::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) void ScrollbarThemeWin::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
{ {
// Just assume a forward track part. We only paint the track as a single piece when there is no thumb. // Just assume a forward track part. We only paint the track as a single piece when there is no thumb.
...@@ -340,10 +370,5 @@ void ScrollbarThemeWin::paintThumb(GraphicsContext* context, Scrollbar* scrollba ...@@ -340,10 +370,5 @@ void ScrollbarThemeWin::paintThumb(GraphicsContext* context, Scrollbar* scrollba
context->releaseWindowsContext(hdc, rect, alphaBlend); context->releaseWindowsContext(hdc, rect, alphaBlend);
} }
bool ScrollbarThemeWin::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
{
return evt.shiftKey() && evt.button() == LeftButton;
}
} }
...@@ -50,6 +50,7 @@ protected: ...@@ -50,6 +50,7 @@ protected:
virtual IntRect trackRect(Scrollbar*, bool painting = false); virtual IntRect trackRect(Scrollbar*, bool painting = false);
virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&); virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&);
virtual bool shouldSnapBackToDragOrigin(Scrollbar*, const PlatformMouseEvent&);
virtual void paintTrackBackground(GraphicsContext*, Scrollbar*, const IntRect&); virtual void paintTrackBackground(GraphicsContext*, Scrollbar*, const IntRect&);
virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment