| /* |
| * Copyright (C) 2007, 2008 Apple Inc. All Rights Reserved. |
| * Copyright (C) 2007 Staikos Computing Services Inc. <info@staikos.net> |
| * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
| * |
| * 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 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 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 "ScrollbarThemeQt.h" |
| |
| #include "GraphicsContext.h" |
| #include "PlatformMouseEvent.h" |
| #include "RenderThemeQt.h" |
| #include "Scrollbar.h" |
| #include "ScrollView.h" |
| |
| #include <QApplication> |
| #include <QDebug> |
| #include <QPainter> |
| #include <QStyle> |
| #include <QStyleOptionSlider> |
| #include <QMenu> |
| |
| namespace WebCore { |
| |
| ScrollbarTheme* ScrollbarTheme::nativeTheme() |
| { |
| static ScrollbarThemeQt theme; |
| return &theme; |
| } |
| |
| ScrollbarThemeQt::~ScrollbarThemeQt() |
| { |
| } |
| |
| static QStyle::SubControl scPart(const ScrollbarPart& part) |
| { |
| switch (part) { |
| case NoPart: |
| return QStyle::SC_None; |
| case BackButtonStartPart: |
| case BackButtonEndPart: |
| return QStyle::SC_ScrollBarSubLine; |
| case BackTrackPart: |
| return QStyle::SC_ScrollBarSubPage; |
| case ThumbPart: |
| return QStyle::SC_ScrollBarSlider; |
| case ForwardTrackPart: |
| return QStyle::SC_ScrollBarAddPage; |
| case ForwardButtonStartPart: |
| case ForwardButtonEndPart: |
| return QStyle::SC_ScrollBarAddLine; |
| } |
| |
| return QStyle::SC_None; |
| } |
| |
| static ScrollbarPart scrollbarPart(const QStyle::SubControl& sc) |
| { |
| switch (sc) { |
| case QStyle::SC_None: |
| return NoPart; |
| case QStyle::SC_ScrollBarSubLine: |
| return BackButtonStartPart; |
| case QStyle::SC_ScrollBarSubPage: |
| return BackTrackPart; |
| case QStyle::SC_ScrollBarSlider: |
| return ThumbPart; |
| case QStyle::SC_ScrollBarAddPage: |
| return ForwardTrackPart; |
| case QStyle::SC_ScrollBarAddLine: |
| return ForwardButtonStartPart; |
| } |
| return NoPart; |
| } |
| |
| static QStyleOptionSlider* styleOptionSlider(Scrollbar* scrollbar, QWidget* widget = 0) |
| { |
| static QStyleOptionSlider opt; |
| if (widget) |
| opt.initFrom(widget); |
| else |
| opt.state |= QStyle::State_Active; |
| |
| opt.state &= ~QStyle::State_HasFocus; |
| |
| opt.rect = scrollbar->frameRect(); |
| if (scrollbar->enabled()) |
| opt.state |= QStyle::State_Enabled; |
| if (scrollbar->controlSize() != RegularScrollbar) |
| opt.state |= QStyle::State_Mini; |
| opt.orientation = (scrollbar->orientation() == VerticalScrollbar) ? Qt::Vertical : Qt::Horizontal; |
| if (scrollbar->orientation() == HorizontalScrollbar) |
| opt.state |= QStyle::State_Horizontal; |
| opt.sliderValue = scrollbar->value(); |
| opt.sliderPosition = opt.sliderValue; |
| opt.pageStep = scrollbar->visibleSize(); |
| opt.singleStep = scrollbar->lineStep(); |
| opt.minimum = 0; |
| opt.maximum = qMax(0, scrollbar->maximum()); |
| ScrollbarPart pressedPart = scrollbar->pressedPart(); |
| ScrollbarPart hoveredPart = scrollbar->hoveredPart(); |
| if (pressedPart != NoPart) { |
| opt.activeSubControls = scPart(scrollbar->pressedPart()); |
| if (pressedPart == BackButtonStartPart || pressedPart == ForwardButtonStartPart || |
| pressedPart == BackButtonEndPart || pressedPart == ForwardButtonEndPart || |
| pressedPart == ThumbPart) |
| opt.state |= QStyle::State_Sunken; |
| } else |
| opt.activeSubControls = scPart(hoveredPart); |
| if (hoveredPart != NoPart) |
| opt.state |= QStyle::State_MouseOver; |
| return &opt; |
| } |
| |
| bool ScrollbarThemeQt::paint(Scrollbar* scrollbar, GraphicsContext* graphicsContext, const IntRect& damageRect) |
| { |
| if (graphicsContext->updatingControlTints()) { |
| scrollbar->invalidateRect(damageRect); |
| return false; |
| } |
| |
| StylePainter p(graphicsContext); |
| if (!p.isValid()) |
| return true; |
| |
| p.painter->save(); |
| QStyleOptionSlider* opt = styleOptionSlider(scrollbar, p.widget); |
| |
| p.painter->setClipRect(opt->rect.intersected(damageRect)); |
| |
| #ifdef Q_WS_MAC |
| p.drawComplexControl(QStyle::CC_ScrollBar, *opt); |
| #else |
| const QPoint topLeft = opt->rect.topLeft(); |
| p.painter->translate(topLeft); |
| opt->rect.moveTo(QPoint(0, 0)); |
| |
| // The QStyle expects the background to be already filled |
| p.painter->fillRect(opt->rect, opt->palette.background()); |
| |
| p.drawComplexControl(QStyle::CC_ScrollBar, *opt); |
| opt->rect.moveTo(topLeft); |
| #endif |
| p.painter->restore(); |
| |
| return true; |
| } |
| |
| ScrollbarPart ScrollbarThemeQt::hitTest(Scrollbar* scrollbar, const PlatformMouseEvent& evt) |
| { |
| QStyleOptionSlider* opt = styleOptionSlider(scrollbar); |
| const QPoint pos = scrollbar->convertFromContainingWindow(evt.pos()); |
| opt->rect.moveTo(QPoint(0, 0)); |
| QStyle::SubControl sc = QApplication::style()->hitTestComplexControl(QStyle::CC_ScrollBar, opt, pos, 0); |
| return scrollbarPart(sc); |
| } |
| |
| bool ScrollbarThemeQt::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt) |
| { |
| // Middle click centers slider thumb (if supported) |
| return QApplication::style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition) && evt.button() == MiddleButton; |
| } |
| |
| void ScrollbarThemeQt::invalidatePart(Scrollbar* scrollbar, ScrollbarPart) |
| { |
| // FIXME: Do more precise invalidation. |
| scrollbar->invalidate(); |
| } |
| |
| int ScrollbarThemeQt::scrollbarThickness(ScrollbarControlSize controlSize) |
| { |
| QStyle* s = QApplication::style(); |
| QStyleOptionSlider o; |
| o.orientation = Qt::Vertical; |
| o.state &= ~QStyle::State_Horizontal; |
| if (controlSize != RegularScrollbar) |
| o.state |= QStyle::State_Mini; |
| return s->pixelMetric(QStyle::PM_ScrollBarExtent, &o, 0); |
| } |
| |
| int ScrollbarThemeQt::thumbPosition(Scrollbar* scrollbar) |
| { |
| if (scrollbar->enabled()) |
| return (int)((float)scrollbar->currentPos() * (trackLength(scrollbar) - thumbLength(scrollbar)) / scrollbar->maximum()); |
| return 0; |
| } |
| |
| int ScrollbarThemeQt::thumbLength(Scrollbar* scrollbar) |
| { |
| QStyleOptionSlider* opt = styleOptionSlider(scrollbar); |
| IntRect thumb = QApplication::style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarSlider, 0); |
| return scrollbar->orientation() == HorizontalScrollbar ? thumb.width() : thumb.height(); |
| } |
| |
| int ScrollbarThemeQt::trackPosition(Scrollbar* scrollbar) |
| { |
| QStyleOptionSlider* opt = styleOptionSlider(scrollbar); |
| IntRect track = QApplication::style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarGroove, 0); |
| return scrollbar->orientation() == HorizontalScrollbar ? track.x() - scrollbar->x() : track.y() - scrollbar->y(); |
| } |
| |
| int ScrollbarThemeQt::trackLength(Scrollbar* scrollbar) |
| { |
| QStyleOptionSlider* opt = styleOptionSlider(scrollbar); |
| IntRect track = QApplication::style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarGroove, 0); |
| return scrollbar->orientation() == HorizontalScrollbar ? track.width() : track.height(); |
| } |
| |
| void ScrollbarThemeQt::paintScrollCorner(ScrollView* scrollView, GraphicsContext* context, const IntRect& rect) |
| { |
| if (context->updatingControlTints()) { |
| scrollView->invalidateRect(rect); |
| return; |
| } |
| |
| #if QT_VERSION < 0x040500 |
| context->fillRect(rect, QApplication::palette().color(QPalette::Normal, QPalette::Window)); |
| #else |
| StylePainter p(context); |
| if (!p.isValid()) |
| return; |
| |
| QStyleOption option; |
| option.rect = rect; |
| p.drawPrimitive(QStyle::PE_PanelScrollAreaCorner, option); |
| #endif |
| } |
| |
| } |
| |