| /* |
| * This file is part of the WebKit project. |
| * |
| * Copyright (C) 2006 Zack Rusin <zack@kde.org> |
| * 2006 Dirk Mueller <mueller@kde.org> |
| * 2006 Nikolas Zimmermann <zimmermann@kde.org> |
| * |
| * All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| */ |
| |
| #include "config.h" |
| |
| #include "RenderThemeQt.h" |
| |
| #include <QApplication> |
| #include <QColor> |
| #include <QDebug> |
| #include <QStyle> |
| #include <QWidget> |
| #include <QPainter> |
| #include <QStyleOptionButton> |
| #include <QStyleOptionFrameV2> |
| |
| #include "Color.h" |
| #include "Document.h" |
| #include "Font.h" |
| #include "RenderTheme.h" |
| #include "GraphicsContext.h" |
| |
| namespace WebCore { |
| |
| RenderTheme* theme() |
| { |
| static RenderThemeQt rt; |
| return &rt; |
| } |
| |
| RenderThemeQt::RenderThemeQt() |
| : RenderTheme() |
| { |
| } |
| |
| bool RenderThemeQt::supportsHover(const RenderStyle*) const |
| { |
| return true; |
| } |
| |
| bool RenderThemeQt::supportsFocusRing(const RenderStyle* style) const |
| { |
| return supportsFocus(style->appearance()); |
| } |
| |
| short RenderThemeQt::baselinePosition(const RenderObject* o) const |
| { |
| if (o->style()->appearance() == CheckboxAppearance || |
| o->style()->appearance() == RadioAppearance) |
| return o->marginTop() + o->height() - 2; // Same as in old khtml |
| return RenderTheme::baselinePosition(o); |
| } |
| |
| bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const |
| { |
| if (!isEnabled(o)) |
| return false; |
| |
| // Checkboxes only have tint when checked. |
| if (o->style()->appearance() == CheckboxAppearance) |
| return isChecked(o); |
| |
| // For now assume other controls have tint if enabled. |
| return true; |
| } |
| |
| bool RenderThemeQt::supportsControlTints() const |
| { |
| return true; |
| } |
| |
| void RenderThemeQt::adjustRepaintRect(const RenderObject* o, IntRect& r) |
| { |
| switch (o->style()->appearance()) { |
| case CheckboxAppearance: { |
| break; |
| } |
| case RadioAppearance: { |
| break; |
| } |
| case PushButtonAppearance: |
| case ButtonAppearance: { |
| break; |
| } |
| case MenulistAppearance: { |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border, |
| const BackgroundLayer& background, const Color& backgroundColor) const |
| { |
| if (style->appearance() == TextFieldAppearance || style->appearance() == TextAreaAppearance) |
| return style->border() != border; |
| |
| return RenderTheme::isControlStyled(style, border, background, backgroundColor); |
| } |
| |
| void RenderThemeQt::paintResizeControl(GraphicsContext*, const IntRect&) |
| { |
| } |
| |
| |
| Color RenderThemeQt::platformActiveSelectionBackgroundColor() const |
| { |
| QPalette pal = QApplication::palette(); |
| return pal.brush(QPalette::Active, QPalette::Highlight).color(); |
| } |
| |
| Color RenderThemeQt::platformInactiveSelectionBackgroundColor() const |
| { |
| QPalette pal = QApplication::palette(); |
| return pal.brush(QPalette::Inactive, QPalette::Highlight).color(); |
| } |
| |
| Color RenderThemeQt::platformActiveSelectionForegroundColor() const |
| { |
| QPalette pal = QApplication::palette(); |
| return pal.brush(QPalette::Active, QPalette::HighlightedText).color(); |
| } |
| |
| Color RenderThemeQt::platformInactiveSelectionForegroundColor() const |
| { |
| QPalette pal = QApplication::palette(); |
| return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color(); |
| } |
| |
| void RenderThemeQt::systemFont(int propId, FontDescription& fontDescription) const |
| { |
| // no-op |
| } |
| |
| int RenderThemeQt::minimumMenuListSize(RenderStyle*) const |
| { |
| const QFontMetrics &fm = QApplication::fontMetrics(); |
| return 7 * fm.width(QLatin1Char('x')); |
| } |
| |
| void RenderThemeQt::adjustSliderThumbSize(RenderObject* o) const |
| { |
| RenderTheme::adjustSliderThumbSize(o); |
| } |
| |
| bool RenderThemeQt::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) |
| { |
| return paintButton(o, i, r); |
| } |
| |
| void RenderThemeQt::setCheckboxSize(RenderStyle* style) const |
| { |
| // If the width and height are both specified, then we have nothing to do. |
| if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) |
| return; |
| |
| // FIXME: A hard-coded size of 13 is used. This is wrong but necessary for now. It matches Firefox. |
| // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for |
| // the higher DPI. Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's |
| // metrics. |
| const int ff = 13; |
| if (style->width().isIntrinsicOrAuto()) |
| style->setWidth(Length(ff, Fixed)); |
| |
| if (style->height().isAuto()) |
| style->setHeight(Length(ff, Fixed)); |
| } |
| |
| bool RenderThemeQt::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) |
| { |
| return paintButton(o, i, r); |
| } |
| |
| void RenderThemeQt::setRadioSize(RenderStyle* style) const |
| { |
| // This is the same as checkboxes. |
| setCheckboxSize(style); |
| } |
| |
| void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const |
| { |
| // Ditch the border. |
| style->resetBorder(); |
| |
| // Height is locked to auto. |
| style->setHeight(Length(Auto)); |
| |
| // White-space is locked to pre |
| style->setWhiteSpace(PRE); |
| |
| setButtonSize(style); |
| |
| setButtonPadding(style); |
| } |
| |
| bool RenderThemeQt::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) |
| { |
| QStyle* style = 0; |
| QPainter* painter = 0; |
| QWidget* widget = 0; |
| |
| if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget)) |
| return true; |
| |
| QStyleOptionButton option; |
| option.initFrom(widget); |
| option.rect = r; |
| |
| // Get the correct theme data for a button |
| EAppearance appearance = applyTheme(option, o); |
| |
| if(appearance == PushButtonAppearance || appearance == ButtonAppearance) |
| style->drawControl(QStyle::CE_PushButton, &option, painter); |
| else if(appearance == RadioAppearance) |
| style->drawControl(QStyle::CE_RadioButton, &option, painter); |
| else if(appearance == CheckboxAppearance) |
| style->drawControl(QStyle::CE_CheckBox, &option, painter); |
| |
| return false; |
| } |
| |
| void RenderThemeQt::setButtonSize(RenderStyle* style) const |
| { |
| setPrimitiveSize(style); |
| } |
| |
| bool RenderThemeQt::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) |
| { |
| QStyle* style = 0; |
| QPainter* painter = 0; |
| QWidget* widget = 0; |
| |
| if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget)) |
| return true; |
| |
| QStyleOptionFrameV2 panel; |
| |
| panel.initFrom(widget); |
| panel.rect = r; |
| panel.state |= QStyle::State_Sunken; |
| panel.features = QStyleOptionFrameV2::None; |
| |
| // Get the correct theme data for a button |
| EAppearance appearance = applyTheme(panel, o); |
| Q_ASSERT(appearance == TextFieldAppearance); |
| |
| // Now paint the text field. |
| style->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, painter, widget); |
| style->drawPrimitive(QStyle::PE_FrameLineEdit, &panel, painter, widget); |
| |
| return false; |
| } |
| |
| void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const |
| { |
| } |
| |
| void RenderThemeQt::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const |
| { |
| style->resetBorder(); |
| |
| // Height is locked to auto. |
| style->setHeight(Length(Auto)); |
| |
| // White-space is locked to pre |
| style->setWhiteSpace(PRE); |
| |
| setPrimitiveSize(style); |
| |
| // Add in the padding that we'd like to use. |
| setPopupPadding(style); |
| |
| // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out |
| // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate |
| // system font for the control size instead. |
| //setFontFromControlSize(selector, style); |
| } |
| |
| bool RenderThemeQt::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) |
| { |
| QStyle* style = 0; |
| QPainter* painter = 0; |
| QWidget* widget = 0; |
| |
| if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget)) |
| return true; |
| |
| QStyleOptionComboBox opt; |
| opt.initFrom(widget); |
| EAppearance appearance = applyTheme(opt, o); |
| const QPoint topLeft = r.topLeft(); |
| painter->translate(topLeft); |
| opt.rect.moveTo(QPoint(0,0)); |
| opt.rect.setSize(r.size()); |
| |
| opt.frame = false; |
| |
| style->drawComplexControl(QStyle::CC_ComboBox, &opt, painter, widget); |
| painter->translate(-topLeft); |
| return false; |
| } |
| |
| |
| bool RenderThemeQt::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& pi, |
| const IntRect& r) |
| { |
| return RenderTheme::paintMenuListButton(o, pi, r); |
| } |
| |
| void RenderThemeQt::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, |
| Element* e) const |
| { |
| RenderTheme::adjustMenuListButtonStyle(selector, style, e); |
| } |
| |
| bool RenderThemeQt::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& pi, |
| const IntRect& r) |
| { |
| return RenderTheme::paintSliderTrack(o, pi, r); |
| } |
| |
| bool RenderThemeQt::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& pi, |
| const IntRect& r) |
| { |
| return RenderTheme::paintSliderThumb(o, pi, r); |
| } |
| |
| bool RenderThemeQt::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& pi, |
| const IntRect& r) |
| { |
| return RenderTheme::paintSearchField(o, pi, r); |
| } |
| |
| void RenderThemeQt::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, |
| Element* e) const |
| { |
| RenderTheme::adjustSearchFieldStyle(selector, style, e); |
| } |
| |
| void RenderThemeQt::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, |
| Element* e) const |
| { |
| RenderTheme::adjustSearchFieldCancelButtonStyle(selector, style, e); |
| } |
| |
| bool RenderThemeQt::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& pi, |
| const IntRect& r) |
| { |
| return RenderTheme::paintSearchFieldCancelButton(o, pi, r); |
| } |
| |
| void RenderThemeQt::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, |
| Element* e) const |
| { |
| RenderTheme::adjustSearchFieldDecorationStyle(selector, style, e); |
| } |
| |
| bool RenderThemeQt::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& pi, |
| const IntRect& r) |
| { |
| return RenderTheme::paintSearchFieldDecoration(o, pi, r); |
| } |
| |
| void RenderThemeQt::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, |
| Element* e) const |
| { |
| RenderTheme::adjustSearchFieldResultsDecorationStyle(selector, style, e); |
| } |
| |
| bool RenderThemeQt::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& pi, |
| const IntRect& r) |
| { |
| return RenderTheme::paintSearchFieldResultsDecoration(o, pi, r); |
| } |
| |
| bool RenderThemeQt::supportsFocus(EAppearance appearance) const |
| { |
| switch (appearance) { |
| case PushButtonAppearance: |
| case ButtonAppearance: |
| case TextFieldAppearance: |
| case MenulistAppearance: |
| case RadioAppearance: |
| case CheckboxAppearance: |
| return true; |
| default: // No for all others... |
| return false; |
| } |
| } |
| |
| bool RenderThemeQt::getStylePainterAndWidgetFromPaintInfo(const RenderObject::PaintInfo& i, QStyle*& style, |
| QPainter*& painter, QWidget*& widget) const |
| { |
| painter = (i.context ? static_cast<QPainter*>(i.context->platformContext()) : 0); |
| widget = (painter ? static_cast<QWidget*>(painter->device()) : 0); |
| style = (widget ? widget->style() : 0); |
| |
| return (painter && widget && style); |
| } |
| |
| EAppearance RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) const |
| { |
| // Default bits: no focus, no mouse over |
| option.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver); |
| |
| if (!isEnabled(o)) |
| option.state &= ~QStyle::State_Enabled; |
| |
| if (isReadOnlyControl(o)) |
| // Readonly is supported on textfields. |
| option.state |= QStyle::State_ReadOnly; |
| |
| if (supportsFocus(o->style()->appearance()) && isFocused(o)) |
| option.state |= QStyle::State_HasFocus; |
| |
| if (isHovered(o)) |
| option.state |= QStyle::State_MouseOver; |
| |
| EAppearance result = o->style()->appearance(); |
| |
| switch (result) { |
| case PushButtonAppearance: |
| case SquareButtonAppearance: |
| case ButtonAppearance: |
| case ButtonBevelAppearance: |
| case ListItemAppearance: |
| case MenulistButtonAppearance: |
| case ScrollbarButtonLeftAppearance: |
| case ScrollbarButtonRightAppearance: |
| case ScrollbarTrackHorizontalAppearance: |
| case ScrollbarTrackVerticalAppearance: |
| case ScrollbarThumbHorizontalAppearance: |
| case ScrollbarThumbVerticalAppearance: |
| case SearchFieldResultsButtonAppearance: |
| case SearchFieldCancelButtonAppearance: { |
| if (isPressed(o)) |
| option.state |= QStyle::State_Sunken; |
| else if (result == PushButtonAppearance) |
| option.state |= QStyle::State_Raised; |
| break; |
| } |
| } |
| |
| if(result == RadioAppearance || result == CheckboxAppearance) |
| option.state |= (isChecked(o) ? QStyle::State_On : QStyle::State_Off); |
| |
| return result; |
| } |
| |
| void RenderThemeQt::setSizeFromFont(RenderStyle* style) const |
| { |
| // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. |
| IntSize size = sizeForFont(style); |
| if (style->width().isIntrinsicOrAuto() && size.width() > 0) |
| style->setWidth(Length(size.width(), Fixed)); |
| if (style->height().isAuto() && size.height() > 0) |
| style->setHeight(Length(size.height(), Fixed)); |
| } |
| |
| IntSize RenderThemeQt::sizeForFont(RenderStyle* style) const |
| { |
| const QFontMetrics fm(style->font().font()); |
| QSize size(0, 0); |
| switch (style->appearance()) { |
| case CheckboxAppearance: { |
| break; |
| } |
| case RadioAppearance: { |
| break; |
| } |
| case PushButtonAppearance: |
| case ButtonAppearance: { |
| QSize sz = fm.size(Qt::TextShowMnemonic, QString::fromLatin1("X")); |
| QStyleOptionButton opt; |
| sz = QApplication::style()->sizeFromContents(QStyle::CT_PushButton, |
| &opt, sz, 0); |
| size.setHeight(sz.height()); |
| break; |
| } |
| case MenulistAppearance: { |
| QSize sz; |
| sz.setHeight(qMax(fm.lineSpacing(), 14) + 2); |
| QStyleOptionComboBox opt; |
| sz = QApplication::style()->sizeFromContents(QStyle::CT_ComboBox, |
| &opt, sz, 0); |
| size.setHeight(sz.height()); |
| break; |
| } |
| case TextFieldAppearance: { |
| const int verticalMargin = 1; |
| const int horizontalMargin = 2; |
| int h = qMax(fm.lineSpacing(), 14) + 2*verticalMargin; |
| int w = fm.width(QLatin1Char('x')) * 17 + 2*horizontalMargin; |
| QStyleOptionFrameV2 opt; |
| opt.lineWidth = QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth, |
| &opt, 0); |
| QSize sz = QApplication::style()->sizeFromContents(QStyle::CT_LineEdit, |
| &opt, |
| QSize(w, h).expandedTo(QApplication::globalStrut()), |
| 0); |
| size.setHeight(sz.height()); |
| break; |
| } |
| default: |
| break; |
| } |
| return size; |
| } |
| |
| void RenderThemeQt::setButtonPadding(RenderStyle* style) const |
| { |
| const int padding = 8; |
| style->setPaddingLeft(Length(padding, Fixed)); |
| style->setPaddingRight(Length(padding, Fixed)); |
| style->setPaddingTop(Length(0, Fixed)); |
| style->setPaddingBottom(Length(0, Fixed)); |
| } |
| |
| void RenderThemeQt::setPopupPadding(RenderStyle* style) const |
| { |
| const int padding = 8; |
| style->setPaddingLeft(Length(padding, Fixed)); |
| QStyleOptionComboBox opt; |
| int w = QApplication::style()->pixelMetric(QStyle::PM_ButtonIconSize, &opt, 0); |
| style->setPaddingRight(Length(padding + w, Fixed)); |
| |
| style->setPaddingTop(Length(1, Fixed)); |
| style->setPaddingBottom(Length(0, Fixed)); |
| } |
| |
| void RenderThemeQt::setPrimitiveSize(RenderStyle* style) const |
| { |
| // If the width and height are both specified, then we have nothing to do. |
| if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) |
| return; |
| |
| // Use the font size to determine the intrinsic width of the control. |
| setSizeFromFont(style); |
| } |
| |
| } |
| |
| // vim: ts=4 sw=4 et |