void PlatformScrollbar::handleMouseMoveEventWhenCapturing(const PlatformMouseEvent& e) { IntPoint pos = convertFromContainingWindow(e.pos()); updateMousePosition(pos.x(), pos.y()); if (m_captureStart != Thumb) { // FIXME: Invalidate only the portions that actually changed invalidate(); return; } int xCancelDistance, yCancelDistance, backgroundSpan, thumbGirth, delta; // NOTE: The cancel distance calculations are based on the behavior of the // MSVC8 main window scrollbar + some guessing/extrapolation if (orientation() == HorizontalScrollbar) { xCancelDistance = kOffEndMultiplier * horizontalScrollbarHeight(); yCancelDistance = kOffSideMultiplier * horizontalScrollbarHeight(); backgroundSpan = m_segmentRects[AfterThumb].right() - m_segmentRects[BeforeThumb].x(); thumbGirth = m_segmentRects[Thumb].right() - m_segmentRects[Thumb].x(); delta = pos.x() - m_dragOrigin.thumbPos; } else { xCancelDistance = kOffSideMultiplier * verticalScrollbarWidth(); yCancelDistance = kOffEndMultiplier * verticalScrollbarWidth(); backgroundSpan = m_segmentRects[AfterThumb].bottom() - m_segmentRects[BeforeThumb].y(); thumbGirth = m_segmentRects[Thumb].bottom() - m_segmentRects[Thumb].y(); delta = pos.y() - m_dragOrigin.thumbPos; } // Snap scrollbar back to drag origin if mouse gets too far away if ((m_lastNativePos.x() < (m_segmentRects[BeforeThumb].x() - xCancelDistance)) || (m_lastNativePos.x() > (m_segmentRects[AfterThumb].right() + xCancelDistance)) || (m_lastNativePos.y() < (m_segmentRects[BeforeThumb].y() - yCancelDistance)) || (m_lastNativePos.y() > (m_segmentRects[AfterThumb].bottom() + yCancelDistance))) delta = 0; // Convert delta from pixel coords to scrollbar logical coords if (backgroundSpan > thumbGirth) { if (setValue(m_dragOrigin.scrollVal + (delta * (m_totalSize - m_visibleSize) / (backgroundSpan - thumbGirth)))) { m_needsLayout = true; // FIXME: Invalidate only the portions that actually changed invalidate(); } } }
PlatformScrollbar::PlatformScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size) : Scrollbar(client, orientation, size) , m_pressedPos(0) , m_pressedPart(QStyle::SC_None) , m_hoveredPart(QStyle::SC_None) , m_scrollTimer(this, &PlatformScrollbar::autoscrollTimerFired) { QStyle *s = QApplication::style(); m_opt.state = QStyle::State_Active | QStyle::State_Enabled; m_opt.sliderValue = m_opt.sliderPosition = 0; m_opt.upsideDown = false; setEnabled(true); if (size != RegularScrollbar) m_opt.state |= QStyle::State_Mini; if (orientation == HorizontalScrollbar) { m_opt.rect.setHeight(horizontalScrollbarHeight(size)); m_opt.orientation = Qt::Horizontal; m_opt.state |= QStyle::State_Horizontal; } else { m_opt.rect.setWidth(verticalScrollbarWidth(size)); m_opt.orientation = Qt::Vertical; m_opt.state &= ~QStyle::State_Horizontal; } }
void PlatformScrollbar::paint(GraphicsContext* graphicsContext, const IntRect& damageRect) { if (controlSize() != RegularScrollbar) { m_opt.state |= QStyle::State_Mini; } else { m_opt.state &= ~QStyle::State_Mini; } m_opt.orientation = (orientation() == VerticalScrollbar) ? Qt::Vertical : Qt::Horizontal; QStyle *s = QApplication::style(); if (orientation() == HorizontalScrollbar) { m_opt.rect.setHeight(horizontalScrollbarHeight(controlSize())); m_opt.state |= QStyle::State_Horizontal; } else { m_opt.rect.setWidth(verticalScrollbarWidth(controlSize())); m_opt.state &= ~QStyle::State_Horizontal; } if (graphicsContext->paintingDisabled() || !m_opt.rect.isValid()) return; QRect clip = m_opt.rect.intersected(damageRect); // Don't paint anything if the scrollbar doesn't intersect the damage rect. if (clip.isEmpty()) return; QPainter *p = graphicsContext->platformContext(); p->save(); p->setClipRect(clip); m_opt.sliderValue = value(); m_opt.sliderPosition = value(); m_opt.pageStep = m_visibleSize; m_opt.singleStep = m_lineStep; m_opt.minimum = 0; m_opt.maximum = qMax(0, m_totalSize - m_visibleSize); if (m_pressedPart != QStyle::SC_None) { m_opt.activeSubControls = m_pressedPart; } else { m_opt.activeSubControls = m_hoveredPart; } const QPoint topLeft = m_opt.rect.topLeft(); #ifdef Q_WS_MAC QApplication::style()->drawComplexControl(QStyle::CC_ScrollBar, &m_opt, p, 0); #else p->translate(topLeft); m_opt.rect.moveTo(QPoint(0, 0)); // The QStyle expects the background to be already filled p->fillRect(m_opt.rect, m_opt.palette.background()); QApplication::style()->drawComplexControl(QStyle::CC_ScrollBar, &m_opt, p, 0); m_opt.rect.moveTo(topLeft); #endif p->restore(); }
void PlatformScrollbar::layout() { #if PLATFORM(WIN_OS) if (!m_needsLayout) return; m_needsLayout = false; const IntRect invalid(-1, -1, 0, 0); if (m_totalSize <= 0) { for (int i = 0; i < NumSegments; ++i) m_segmentRects[i] = invalid; return; } int buttonGirth, backgroundSpan, thumbGirth; RECT box = {0}; LONG* changingCoord1, * changingCoord2; // For both orientations, we allow the buttonGirth to determine the // backgroundSpan directly, to avoid rounding errors. if (orientation() == HorizontalScrollbar) { buttonGirth = scrollButtonGirth(SM_CXHSCROLL, width(), &backgroundSpan); thumbGirth = scrollThumbGirth(SM_CXHTHUMB, backgroundSpan); box.bottom += horizontalScrollbarHeight(); changingCoord1 = &box.left; changingCoord2 = &box.right; } else { buttonGirth = scrollButtonGirth(SM_CYVSCROLL, height(), &backgroundSpan); thumbGirth = scrollThumbGirth(SM_CYVTHUMB, backgroundSpan); box.right += verticalScrollbarWidth(); changingCoord1 = &box.top; changingCoord2 = &box.bottom; } // Scrollbar: |<|--------|XXX|------|>| // Start arrow: |<| *changingCoord2 += buttonGirth; m_segmentRects[Arrow1] = gfx::RECTToSkIRect(box); if (thumbGirth >= backgroundSpan) { if (backgroundSpan == 0) { m_segmentRects[Track] = invalid; } else { // Track: |-------------------| *changingCoord1 = *changingCoord2; *changingCoord2 += backgroundSpan; m_segmentRects[Track] = gfx::RECTToSkIRect(box); } m_segmentRects[BeforeThumb] = invalid; m_segmentRects[Thumb] = invalid; m_segmentRects[AfterThumb] = invalid; } else { m_segmentRects[Track] = invalid; const int thumbOffset = (m_totalSize <= m_visibleSize) ? 0 : (value() * (backgroundSpan - thumbGirth) / (m_totalSize - m_visibleSize)); // Before thumb: |--------| *changingCoord1 = *changingCoord2; *changingCoord2 += thumbOffset; m_segmentRects[BeforeThumb] = gfx::RECTToSkIRect(box); // Thumb: |XXX| *changingCoord1 = *changingCoord2; *changingCoord2 += thumbGirth; m_segmentRects[Thumb] = gfx::RECTToSkIRect(box); // After thumb: |------| *changingCoord1 = *changingCoord2; *changingCoord2 += backgroundSpan - (thumbOffset + thumbGirth); m_segmentRects[AfterThumb] = gfx::RECTToSkIRect(box); } // End arrow: |>| *changingCoord1 = *changingCoord2; *changingCoord2 += buttonGirth; m_segmentRects[Arrow2] = gfx::RECTToSkIRect(box); // Changed layout, so need to update m_mouseOver and m_autorepeatTimer updateMousePositionInternal(); // DO NOT invalidate() here. We already invalidate()d for this layout when // setting m_needsLayout = true; by the time we reach this point, we're // called by paint(), so invalidate() is not only unnecessary but will // waste effort. #endif }
int PlatformScrollbar::width() const { return orientation() == VerticalScrollbar ? verticalScrollbarWidth(controlSize()) : Widget::width(); }