/* * This file is part of the WebKit project. * * Copyright (C) 2006 Zack Rusin * 2006 Dirk Mueller * 2006 Nikolas Zimmermann * * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */ #include "config.h" #include "RenderThemeQt.h" #include #include #include #include #include #include #include #include #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(i.context->platformContext()) : 0); widget = (painter ? static_cast(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