2006-08-28 Nikolas Zimmermann <zimmermann@kde.org>
[WebKit-https.git] / WebCore / platform / qt / RenderThemeQt.cpp
1 /*
2  * This file is part of the WebKit project.
3  *
4  * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
5  *               2006 Nikolas Zimmermann <zimmermann@kde.org>
6  *
7  * All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *
24  */
25
26 #include "config.h"
27
28 #include <QStyle>
29 #include <QWidget>
30 #include <QPainter>
31 #include <QStyleOptionButton>
32
33 #include "Document.h"
34 #include "RenderTheme.h"
35 #include "GraphicsContext.h"
36 #include "RenderPopupMenuQt.h"
37
38 #define notImplemented() do { fprintf(stderr, "FIXME: UNIMPLEMENTED: %s:%d\n", __FILE__, __LINE__); } while(0)
39
40 namespace WebCore {
41
42 class RenderThemeQt : public RenderTheme
43 {
44 public:
45     RenderThemeQt() : RenderTheme() { }
46
47     // A method asking if the theme's controls actually care about redrawing when hovered.
48     virtual bool supportsHover(const RenderStyle*) const { return true; }
49
50     virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
51     {
52         return paintButton(o, i, r);
53     }
54  
55     virtual void setCheckboxSize(RenderStyle*) const;
56
57     virtual bool paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
58     {
59         return paintButton(o, i, r);
60     }
61
62     virtual void setRadioSize(RenderStyle*) const;
63
64     virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
65     virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
66
67     virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
68     virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
69
70     virtual bool isControlStyled(const RenderStyle*, const BorderData&,
71                                  const BackgroundLayer&, const Color&) const;
72
73     virtual bool controlSupportsTints(const RenderObject*) const;
74
75     virtual void systemFont(int propId, FontDescription&) const;
76     virtual RenderPopupMenu* createPopupMenu(RenderArena*, Document*, RenderMenuList*);
77     
78 private:
79     void addIntrinsicMargins(RenderStyle*) const;
80     void close();
81
82     bool supportsFocus(EAppearance) const;
83
84     bool getStylePainterAndWidgetFromPaintInfo(const RenderObject::PaintInfo&, QStyle*&, QPainter*&, QWidget*&) const;
85     EAppearance applyTheme(QStyleOption&, RenderObject*) const;
86 };
87
88 RenderTheme* theme()
89 {
90     static RenderThemeQt rt;
91     return &rt;
92 }
93
94 bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData& border,
95                                      const BackgroundLayer& background, const Color& backgroundColor) const
96 {
97     if (style->appearance() == TextFieldAppearance || style->appearance() == TextAreaAppearance)
98         return style->border() != border;
99
100     return RenderTheme::isControlStyled(style, border, background, backgroundColor);
101 }
102
103 bool RenderThemeQt::controlSupportsTints(const RenderObject* o) const
104 {
105     if (!isEnabled(o))
106         return false;
107
108     // Checkboxes only have tint when checked.
109     if (o->style()->appearance() == CheckboxAppearance)
110         return isChecked(o);
111
112     // For now assume other controls have tint if enabled.
113     return true;
114 }
115
116 void RenderThemeQt::systemFont(int propId, FontDescription& fontDescription) const
117 {
118     // no-op
119 }
120
121 RenderPopupMenu* RenderThemeQt::createPopupMenu(RenderArena* arena, Document* doc, RenderMenuList* menuList)
122 {
123     return new (arena) RenderPopupMenuQt(doc, menuList);
124 }
125
126 void RenderThemeQt::addIntrinsicMargins(RenderStyle* style) const
127 {
128     // Cut out the intrinsic margins completely if we end up using a small font size
129     if (style->fontSize() < 11)
130         return;
131
132     // Intrinsic margin value.
133     const int m = 2;
134
135     // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
136     if (style->width().isIntrinsicOrAuto()) {
137         if (style->marginLeft().quirk())
138             style->setMarginLeft(Length(m, Fixed));
139
140         if (style->marginRight().quirk())
141             style->setMarginRight(Length(m, Fixed));
142     }
143
144     if (style->height().isAuto()) {
145         if (style->marginTop().quirk())
146             style->setMarginTop(Length(m, Fixed));
147
148         if (style->marginBottom().quirk())
149             style->setMarginBottom(Length(m, Fixed));
150     }
151 }
152
153 bool RenderThemeQt::getStylePainterAndWidgetFromPaintInfo(const RenderObject::PaintInfo& i, QStyle*& style, QPainter*& painter, QWidget*& widget) const
154 {
155     painter = (i.p ? static_cast<QPainter*>(i.p->platformContext()) : 0);
156     widget = (painter ? static_cast<QWidget*>(painter->device()) : 0);
157     style = (widget ? widget->style() : 0);
158
159     return (painter && widget && style);
160 }
161
162 void RenderThemeQt::setCheckboxSize(RenderStyle* style) const
163 {
164     // If the width and height are both specified, then we have nothing to do.
165     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
166         return;
167
168     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary for now.  It matches Firefox.
169     // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
170     // the higher DPI.  Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
171     // metrics.
172     if (style->width().isIntrinsicOrAuto())
173         style->setWidth(Length(13, Fixed));
174
175     if (style->height().isAuto())
176         style->setHeight(Length(13, Fixed));
177 }
178
179 void RenderThemeQt::setRadioSize(RenderStyle* style) const
180 {
181     // This is the same as checkboxes.
182     setCheckboxSize(style);
183 }
184
185 bool RenderThemeQt::supportsFocus(EAppearance appearance) const
186 {
187     switch (appearance) {
188         case PushButtonAppearance:
189         case ButtonAppearance:
190         case TextFieldAppearance:
191             return true;
192         default: // No for all others...
193             return false;
194     }
195 }
196
197 EAppearance RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) const
198 {
199     // Default bits: no focus, no mouse over
200     option.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver);
201
202     if (!isEnabled(o))
203         option.state &= ~QStyle::State_Enabled;
204
205     if (isReadOnlyControl(o))
206         // Readonly is supported on textfields.
207         option.state |= QStyle::State_ReadOnly;
208
209     if (supportsFocus(o->style()->appearance()) && isFocused(o))
210         option.state |= QStyle::State_HasFocus;
211
212     if (isHovered(o))
213         option.state |= QStyle::State_MouseOver;
214
215     if (isPressed(o))
216         option.state |= QStyle::State_Sunken;
217
218     EAppearance result = o->style()->appearance();
219     if(result == RadioAppearance || result == CheckboxAppearance)
220         option.state |= (isChecked(o) ? QStyle::State_On : QStyle::State_Off);
221
222     return result;
223 }
224
225 void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
226 {
227     addIntrinsicMargins(style);
228 }
229
230 bool RenderThemeQt::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
231 {
232     QStyle* style = 0;
233     QPainter* painter = 0;
234     QWidget* widget = 0;
235     
236     if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget))
237         return true;
238     
239     QStyleOptionButton option;
240     option.initFrom(widget);
241     option.rect = r;
242
243     // Get the correct theme data for a button
244     EAppearance appearance = applyTheme(option, o);
245   
246     if(appearance == PushButtonAppearance || appearance == ButtonAppearance)
247         style->drawControl(QStyle::CE_PushButton, &option, painter);
248     else if(appearance == RadioAppearance)
249         style->drawControl(QStyle::CE_RadioButton, &option, painter);
250     else if(appearance == CheckboxAppearance)
251         style->drawControl(QStyle::CE_CheckBox, &option, painter);
252
253     return false;
254 }
255
256 void RenderThemeQt::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
257 {
258     addIntrinsicMargins(style);
259 }
260
261 bool RenderThemeQt::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
262 {
263     QStyle* style = 0;
264     QPainter* painter = 0;
265     QWidget* widget = 0;
266     
267     if (!getStylePainterAndWidgetFromPaintInfo(i, style, painter, widget))
268         return true;
269   
270     QStyleOption option;
271
272     // Get the correct theme data for a button
273     EAppearance appearance = applyTheme(option, o);
274     Q_ASSERT(appearance == TextFieldAppearance);
275
276     // Now paint the text field.
277     // FIXME: this is not enough for sure! (use 'option'...)
278     painter->drawRect(r);
279
280     return false;
281 }
282
283 }
284
285 // vim: ts=4 sw=4 et