source: trunk/src/gui/styles/qstylesheetstyle.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 234.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <qglobal.h>
43
44#ifndef QT_NO_STYLE_STYLESHEET
45
46#include "qstylesheetstyle_p.h"
47#include "private/qcssutil_p.h"
48#include <qdebug.h>
49#include <qapplication.h>
50#include <qmenu.h>
51#include <qmenubar.h>
52#include <qpainter.h>
53#include <qstyleoption.h>
54#include <qlineedit.h>
55#include <qwindowsstyle.h>
56#include <qcombobox.h>
57#include <qwindowsstyle.h>
58#include <qplastiquestyle.h>
59#include "private/qcssparser_p.h"
60#include "private/qmath_p.h"
61#include <qabstractscrollarea.h>
62#include "private/qabstractscrollarea_p.h"
63#include <qtooltip.h>
64#include <qshareddata.h>
65#include <qradiobutton.h>
66#include <qtoolbutton.h>
67#include <qscrollbar.h>
68#include <qstring.h>
69#include <qfile.h>
70#include <qcheckbox.h>
71#include <qstatusbar.h>
72#include <qheaderview.h>
73#include <qprogressbar.h>
74#include <private/qwindowsstyle_p.h>
75#include <qtabbar.h>
76#include <QMetaProperty>
77#include <qmainwindow.h>
78#include <qdockwidget.h>
79#include <qmdisubwindow.h>
80#include <qdialog.h>
81#include <private/qwidget_p.h>
82#include <QAbstractSpinBox>
83#include <QLabel>
84
85#include <limits.h>
86
87QT_BEGIN_NAMESPACE
88
89using namespace QCss;
90
91
92class QStyleSheetStylePrivate : public QWindowsStylePrivate
93{
94 Q_DECLARE_PUBLIC(QStyleSheetStyle)
95public:
96 QStyleSheetStylePrivate() { }
97};
98
99
100static QHash<const QWidget *, QVector<StyleRule> > *styleRulesCache = 0;
101static QHash<const QWidget *, QHash<int, bool> > *hasStyleRuleCache = 0;
102typedef QHash<int, QHash<quint64, QRenderRule> > QRenderRules;
103static QHash<const QWidget *, QRenderRules> *renderRulesCache = 0;
104static QHash<const QWidget *, QPalette> *customPaletteWidgets = 0; // widgets whose palette we tampered
105static QHash<const void *, StyleSheet> *styleSheetCache = 0; // parsed style sheets
106static QSet<const QWidget *> *autoFillDisabledWidgets = 0;
107
108
109/* RECURSION_GUARD:
110 * the QStyleSheetStyle is a proxy. If used with others proxy style, we may end up with something like:
111 * QStyleSheetStyle -> ProxyStyle -> QStyleSheetStyle -> OriginalStyle
112 * Recursion may happen if the style call the widget()->style() again.
113 * Not to mention the performence penalty of having two lookup of rules.
114 *
115 * The first instance of QStyleSheetStyle will set globalStyleSheetStyle to itself. The second one
116 * will notice the globalStyleSheetStyle is not istelf and call its base style directly.
117 */
118static const QStyleSheetStyle *globalStyleSheetStyle = 0;
119class QStyleSheetStyleRecursionGuard
120{
121 public:
122 QStyleSheetStyleRecursionGuard(const QStyleSheetStyle *that)
123 : guarded(globalStyleSheetStyle == 0)
124 {
125 if (guarded) globalStyleSheetStyle = that;
126 }
127 ~QStyleSheetStyleRecursionGuard() { if (guarded) globalStyleSheetStyle = 0; }
128 bool guarded;
129};
130#define RECURSION_GUARD(RETURN) \
131 if (globalStyleSheetStyle != 0 && globalStyleSheetStyle != this) { RETURN; } \
132 QStyleSheetStyleRecursionGuard recursion_guard(this);
133
134#define ceil(x) ((int)(x) + ((x) > 0 && (x) != (int)(x)))
135
136enum PseudoElement {
137 PseudoElement_None,
138 PseudoElement_DownArrow,
139 PseudoElement_UpArrow,
140 PseudoElement_LeftArrow,
141 PseudoElement_RightArrow,
142 PseudoElement_Indicator,
143 PseudoElement_ExclusiveIndicator,
144 PseudoElement_PushButtonMenuIndicator,
145 PseudoElement_ComboBoxDropDown,
146 PseudoElement_ComboBoxArrow,
147 PseudoElement_Item,
148 PseudoElement_SpinBoxUpButton,
149 PseudoElement_SpinBoxUpArrow,
150 PseudoElement_SpinBoxDownButton,
151 PseudoElement_SpinBoxDownArrow,
152 PseudoElement_GroupBoxTitle,
153 PseudoElement_GroupBoxIndicator,
154 PseudoElement_ToolButtonMenu,
155 PseudoElement_ToolButtonMenuArrow,
156 PseudoElement_ToolButtonDownArrow,
157 PseudoElement_ToolBoxTab,
158 PseudoElement_ScrollBarSlider,
159 PseudoElement_ScrollBarAddPage,
160 PseudoElement_ScrollBarSubPage,
161 PseudoElement_ScrollBarAddLine,
162 PseudoElement_ScrollBarSubLine,
163 PseudoElement_ScrollBarFirst,
164 PseudoElement_ScrollBarLast,
165 PseudoElement_ScrollBarUpArrow,
166 PseudoElement_ScrollBarDownArrow,
167 PseudoElement_ScrollBarLeftArrow,
168 PseudoElement_ScrollBarRightArrow,
169 PseudoElement_SplitterHandle,
170 PseudoElement_ToolBarHandle,
171 PseudoElement_ToolBarSeparator,
172 PseudoElement_MenuScroller,
173 PseudoElement_MenuTearoff,
174 PseudoElement_MenuCheckMark,
175 PseudoElement_MenuSeparator,
176 PseudoElement_MenuIcon,
177 PseudoElement_MenuRightArrow,
178 PseudoElement_TreeViewBranch,
179 PseudoElement_HeaderViewSection,
180 PseudoElement_HeaderViewUpArrow,
181 PseudoElement_HeaderViewDownArrow,
182 PseudoElement_ProgressBarChunk,
183 PseudoElement_TabBarTab,
184 PseudoElement_TabBarScroller,
185 PseudoElement_TabBarTear,
186 PseudoElement_SliderGroove,
187 PseudoElement_SliderHandle,
188 PseudoElement_SliderAddPage,
189 PseudoElement_SliderSubPage,
190 PseudoElement_SliderTickmark,
191 PseudoElement_TabWidgetPane,
192 PseudoElement_TabWidgetTabBar,
193 PseudoElement_TabWidgetLeftCorner,
194 PseudoElement_TabWidgetRightCorner,
195 PseudoElement_DockWidgetTitle,
196 PseudoElement_DockWidgetCloseButton,
197 PseudoElement_DockWidgetFloatButton,
198 PseudoElement_DockWidgetSeparator,
199 PseudoElement_MdiCloseButton,
200 PseudoElement_MdiMinButton,
201 PseudoElement_MdiNormalButton,
202 PseudoElement_TitleBar,
203 PseudoElement_TitleBarCloseButton,
204 PseudoElement_TitleBarMinButton,
205 PseudoElement_TitleBarMaxButton,
206 PseudoElement_TitleBarShadeButton,
207 PseudoElement_TitleBarUnshadeButton,
208 PseudoElement_TitleBarNormalButton,
209 PseudoElement_TitleBarContextHelpButton,
210 PseudoElement_TitleBarSysMenu,
211 PseudoElement_ViewItem,
212 PseudoElement_ViewItemIcon,
213 PseudoElement_ViewItemText,
214 PseudoElement_ViewItemIndicator,
215 PseudoElement_ScrollAreaCorner,
216 NumPseudoElements
217};
218
219struct PseudoElementInfo {
220 QStyle::SubControl subControl;
221 const char *name;
222};
223
224static const PseudoElementInfo knownPseudoElements[NumPseudoElements] = {
225 { QStyle::SC_None, "", },
226 { QStyle::SC_None, "down-arrow" },
227 { QStyle::SC_None, "up-arrow" },
228 { QStyle::SC_None, "left-arrow" },
229 { QStyle::SC_None, "right-arrow" },
230 { QStyle::SC_None, "indicator" },
231 { QStyle::SC_None, "indicator" },
232 { QStyle::SC_None, "menu-indicator" },
233 { QStyle::SC_ComboBoxArrow, "drop-down" },
234 { QStyle::SC_ComboBoxArrow, "down-arrow" },
235 { QStyle::SC_None, "item" },
236 { QStyle::SC_SpinBoxUp, "up-button" },
237 { QStyle::SC_SpinBoxUp, "up-arrow" },
238 { QStyle::SC_SpinBoxDown, "down-button" },
239 { QStyle::SC_SpinBoxDown, "down-arrow" },
240 { QStyle::SC_GroupBoxLabel, "title" },
241 { QStyle::SC_GroupBoxCheckBox, "indicator" },
242 { QStyle::SC_ToolButtonMenu, "menu-button" },
243 { QStyle::SC_ToolButtonMenu, "menu-arrow" },
244 { QStyle::SC_None, "menu-indicator" },
245 { QStyle::SC_None, "tab" },
246 { QStyle::SC_ScrollBarSlider, "handle" },
247 { QStyle::SC_ScrollBarAddPage, "add-page" },
248 { QStyle::SC_ScrollBarSubPage, "sub-page" },
249 { QStyle::SC_ScrollBarAddLine, "add-line" },
250 { QStyle::SC_ScrollBarSubLine, "sub-line" },
251 { QStyle::SC_ScrollBarFirst, "first" },
252 { QStyle::SC_ScrollBarLast, "last" },
253 { QStyle::SC_ScrollBarSubLine, "up-arrow" },
254 { QStyle::SC_ScrollBarAddLine, "down-arrow" },
255 { QStyle::SC_ScrollBarSubLine, "left-arrow" },
256 { QStyle::SC_ScrollBarAddLine, "right-arrow" },
257 { QStyle::SC_None, "handle" },
258 { QStyle::SC_None, "handle" },
259 { QStyle::SC_None, "separator" },
260 { QStyle::SC_None, "scroller" },
261 { QStyle::SC_None, "tearoff" },
262 { QStyle::SC_None, "indicator" },
263 { QStyle::SC_None, "separator" },
264 { QStyle::SC_None, "icon" },
265 { QStyle::SC_None, "right-arrow" },
266 { QStyle::SC_None, "branch" },
267 { QStyle::SC_None, "section" },
268 { QStyle::SC_None, "down-arrow" },
269 { QStyle::SC_None, "up-arrow" },
270 { QStyle::SC_None, "chunk" },
271 { QStyle::SC_None, "tab" },
272 { QStyle::SC_None, "scroller" },
273 { QStyle::SC_None, "tear" },
274 { QStyle::SC_SliderGroove, "groove" },
275 { QStyle::SC_SliderHandle, "handle" },
276 { QStyle::SC_None, "add-page" },
277 { QStyle::SC_None, "sub-page"},
278 { QStyle::SC_SliderTickmarks, "tick-mark" },
279 { QStyle::SC_None, "pane" },
280 { QStyle::SC_None, "tab-bar" },
281 { QStyle::SC_None, "left-corner" },
282 { QStyle::SC_None, "right-corner" },
283 { QStyle::SC_None, "title" },
284 { QStyle::SC_None, "close-button" },
285 { QStyle::SC_None, "float-button" },
286 { QStyle::SC_None, "separator" },
287 { QStyle::SC_MdiCloseButton, "close-button" },
288 { QStyle::SC_MdiMinButton, "minimize-button" },
289 { QStyle::SC_MdiNormalButton, "normal-button" },
290 { QStyle::SC_TitleBarLabel, "title" },
291 { QStyle::SC_TitleBarCloseButton, "close-button" },
292 { QStyle::SC_TitleBarMinButton, "minimize-button" },
293 { QStyle::SC_TitleBarMaxButton, "maximize-button" },
294 { QStyle::SC_TitleBarShadeButton, "shade-button" },
295 { QStyle::SC_TitleBarUnshadeButton, "unshade-button" },
296 { QStyle::SC_TitleBarNormalButton, "normal-button" },
297 { QStyle::SC_TitleBarContextHelpButton, "contexthelp-button" },
298 { QStyle::SC_TitleBarSysMenu, "sys-menu" },
299 { QStyle::SC_None, "item" },
300 { QStyle::SC_None, "icon" },
301 { QStyle::SC_None, "text" },
302 { QStyle::SC_None, "indicator" } ,
303 { QStyle::SC_None, "corner" }
304};
305
306
307struct QStyleSheetBorderImageData : public QSharedData
308{
309 QStyleSheetBorderImageData()
310 : horizStretch(QCss::TileMode_Unknown), vertStretch(QCss::TileMode_Unknown)
311 {
312 for (int i = 0; i < 4; i++)
313 cuts[i] = -1;
314 }
315 QPixmap topEdge, bottomEdge, leftEdge, rightEdge, middle;
316 QRect topEdgeRect, bottomEdgeRect, leftEdgeRect, rightEdgeRect, middleRect;
317 QRect topLeftCorner, topRightCorner, bottomRightCorner, bottomLeftCorner;
318 int cuts[4];
319 QPixmap pixmap;
320 QImage image;
321 QCss::TileMode horizStretch, vertStretch;
322
323 void cutBorderImage();
324};
325
326struct QStyleSheetBackgroundData : public QSharedData
327{
328 QStyleSheetBackgroundData(const QBrush& b, const QPixmap& p, QCss::Repeat r,
329 Qt::Alignment a, QCss::Origin o, Attachment t, QCss::Origin c)
330 : brush(b), pixmap(p), repeat(r), position(a), origin(o), attachment(t), clip(c) { }
331
332 bool isTransparent() const {
333 if (brush.style() != Qt::NoBrush)
334 return !brush.isOpaque();
335 return pixmap.isNull() ? false : pixmap.hasAlpha();
336 }
337 QBrush brush;
338 QPixmap pixmap;
339 QCss::Repeat repeat;
340 Qt::Alignment position;
341 QCss::Origin origin;
342 QCss::Attachment attachment;
343 QCss::Origin clip;
344};
345
346struct QStyleSheetBorderData : public QSharedData
347{
348 QStyleSheetBorderData() : bi(0)
349 {
350 for (int i = 0; i < 4; i++) {
351 borders[i] = 0;
352 styles[i] = QCss::BorderStyle_None;
353 }
354 }
355
356 QStyleSheetBorderData(int *b, QBrush *c, QCss::BorderStyle *s, QSize *r) : bi(0)
357 {
358 for (int i = 0; i < 4; i++) {
359 borders[i] = b[i];
360 styles[i] = s[i];
361 colors[i] = c[i];
362 radii[i] = r[i];
363 }
364 }
365
366 int borders[4];
367 QBrush colors[4];
368 QCss::BorderStyle styles[4];
369 QSize radii[4]; // topleft, topright, bottomleft, bottomright
370
371 const QStyleSheetBorderImageData *borderImage() const
372 { return bi; }
373 bool hasBorderImage() const { return bi!=0; }
374
375 QSharedDataPointer<QStyleSheetBorderImageData> bi;
376
377 bool isOpaque() const
378 {
379 for (int i = 0; i < 4; i++) {
380 if (styles[i] == QCss::BorderStyle_Native || styles[i] == QCss::BorderStyle_None)
381 continue;
382 if (styles[i] >= QCss::BorderStyle_Dotted && styles[i] <= QCss::BorderStyle_DotDotDash
383 && styles[i] != BorderStyle_Solid)
384 return false;
385 if (!colors[i].isOpaque())
386 return false;
387 if (!radii[i].isEmpty())
388 return false;
389 }
390 if (bi != 0 && bi->pixmap.hasAlpha())
391 return false;
392 return true;
393 }
394};
395
396
397struct QStyleSheetOutlineData : public QStyleSheetBorderData
398{
399 QStyleSheetOutlineData()
400 {
401 for (int i = 0; i < 4; i++) {
402 offsets[i] = 0;
403 }
404 }
405
406 QStyleSheetOutlineData(int *b, QBrush *c, QCss::BorderStyle *s, QSize *r, int *o)
407 : QStyleSheetBorderData(b, c, s, r)
408 {
409 for (int i = 0; i < 4; i++) {
410 offsets[i] = o[i];
411 }
412 }
413
414 int offsets[4];
415};
416
417struct QStyleSheetBoxData : public QSharedData
418{
419 QStyleSheetBoxData(int *m, int *p, int s) : spacing(s)
420 {
421 for (int i = 0; i < 4; i++) {
422 margins[i] = m[i];
423 paddings[i] = p[i];
424 }
425 }
426
427 int margins[4];
428 int paddings[4];
429
430 int spacing;
431};
432
433struct QStyleSheetPaletteData : public QSharedData
434{
435 QStyleSheetPaletteData(const QBrush &fg, const QBrush &sfg, const QBrush &sbg,
436 const QBrush &abg)
437 : foreground(fg), selectionForeground(sfg), selectionBackground(sbg),
438 alternateBackground(abg) { }
439
440 QBrush foreground;
441 QBrush selectionForeground;
442 QBrush selectionBackground;
443 QBrush alternateBackground;
444};
445
446struct QStyleSheetGeometryData : public QSharedData
447{
448 QStyleSheetGeometryData(int w, int h, int minw, int minh, int maxw, int maxh)
449 : minWidth(minw), minHeight(minh), width(w), height(h), maxWidth(maxw), maxHeight(maxh) { }
450
451 int minWidth, minHeight, width, height, maxWidth, maxHeight;
452};
453
454struct QStyleSheetPositionData : public QSharedData
455{
456 QStyleSheetPositionData(int l, int t, int r, int b, Origin o, Qt::Alignment p, QCss::PositionMode m, Qt::Alignment a = 0)
457 : left(l), top(t), bottom(b), right(r), origin(o), position(p), mode(m), textAlignment(a) { }
458
459 int left, top, bottom, right;
460 Origin origin;
461 Qt::Alignment position;
462 QCss::PositionMode mode;
463 Qt::Alignment textAlignment;
464};
465
466struct QStyleSheetImageData : public QSharedData
467{
468 QStyleSheetImageData(const QIcon &i, Qt::Alignment a, const QSize &sz)
469 : icon(i), alignment(a), size(sz) { }
470
471 QIcon icon;
472 Qt::Alignment alignment;
473 QSize size;
474};
475
476class QRenderRule
477{
478public:
479 QRenderRule() : features(0), hasFont(false), pal(0), b(0), bg(0), bd(0), ou(0), geo(0), p(0), img(0), clipset(0) { }
480 QRenderRule(const QVector<QCss::Declaration> &, const QWidget *);
481 ~QRenderRule() { }
482
483 QRect borderRect(const QRect &r) const;
484 QRect outlineRect(const QRect &r) const;
485 QRect paddingRect(const QRect &r) const;
486 QRect contentsRect(const QRect &r) const;
487
488 enum { Margin = 1, Border = 2, Padding = 4, All=Margin|Border|Padding };
489 QRect boxRect(const QRect &r, int flags = All) const;
490 QSize boxSize(const QSize &s, int flags = All) const;
491 QRect originRect(const QRect &rect, Origin origin) const;
492
493 QPainterPath borderClip(QRect rect);
494 void drawBorder(QPainter *, const QRect&);
495 void drawOutline(QPainter *, const QRect&);
496 void drawBorderImage(QPainter *, const QRect&);
497 void drawBackground(QPainter *, const QRect&, const QPoint& = QPoint(0, 0));
498 void drawBackgroundImage(QPainter *, const QRect&, QPoint = QPoint(0, 0));
499 void drawFrame(QPainter *, const QRect&);
500 void drawImage(QPainter *p, const QRect &rect);
501 void drawRule(QPainter *, const QRect&);
502 void configurePalette(QPalette *, QPalette::ColorGroup, const QWidget *, bool);
503 void configurePalette(QPalette *p, QPalette::ColorRole fr, QPalette::ColorRole br);
504
505 const QStyleSheetPaletteData *palette() const { return pal; }
506 const QStyleSheetBoxData *box() const { return b; }
507 const QStyleSheetBackgroundData *background() const { return bg; }
508 const QStyleSheetBorderData *border() const { return bd; }
509 const QStyleSheetOutlineData *outline() const { return ou; }
510 const QStyleSheetGeometryData *geometry() const { return geo; }
511 const QStyleSheetPositionData *position() const { return p; }
512
513 bool hasPalette() const { return pal != 0; }
514 bool hasBackground() const { return bg != 0 && (!bg->pixmap.isNull() || bg->brush.style() != Qt::NoBrush); }
515 bool hasGradientBackground() const { return bg && bg->brush.style() >= Qt::LinearGradientPattern
516 && bg->brush.style() <= Qt::ConicalGradientPattern; }
517
518 bool hasNativeBorder() const {
519 return bd == 0
520 || (!bd->hasBorderImage() && bd->styles[0] == BorderStyle_Native);
521 }
522
523 bool hasNativeOutline() const {
524 return (ou == 0
525 || (!ou->hasBorderImage() && ou->styles[0] == BorderStyle_Native));
526 }
527
528 bool baseStyleCanDraw() const {
529 if (!hasBackground() || (background()->brush.style() == Qt::NoBrush && bg->pixmap.isNull()))
530 return true;
531 if (bg && !bg->pixmap.isNull())
532 return false;
533 if (hasGradientBackground())
534 return features & StyleFeature_BackgroundGradient;
535 return features & StyleFeature_BackgroundColor;
536 }
537
538 bool hasBox() const { return b != 0; }
539 bool hasBorder() const { return bd != 0; }
540 bool hasOutline() const { return ou != 0; }
541 bool hasPosition() const { return p != 0; }
542 bool hasGeometry() const { return geo != 0; }
543 bool hasDrawable() const { return !hasNativeBorder() || hasBackground() || hasImage(); }
544 bool hasImage() const { return img != 0; }
545
546 QSize minimumContentsSize() const
547 { return geo ? QSize(geo->minWidth, geo->minHeight) : QSize(0, 0); }
548 QSize minimumSize() const
549 { return boxSize(minimumContentsSize()); }
550
551 QSize contentsSize() const
552 { return geo ? QSize(geo->width, geo->height)
553 : ((img && img->size.isValid()) ? img->size : QSize()); }
554 QSize contentsSize(const QSize &sz) const
555 {
556 QSize csz = contentsSize();
557 if (csz.width() == -1) csz.setWidth(sz.width());
558 if (csz.height() == -1) csz.setHeight(sz.height());
559 return csz;
560 }
561 bool hasContentsSize() const
562 { return (geo && (geo->width != -1 || geo->height != -1)) || (img && img->size.isValid()); }
563
564 QSize size() const { return boxSize(contentsSize()); }
565 QSize size(const QSize &sz) const { return boxSize(contentsSize(sz)); }
566 QSize adjustSize(const QSize &sz)
567 {
568 if (!geo)
569 return sz;
570 QSize csz = contentsSize();
571 if (csz.width() == -1) csz.setWidth(sz.width());
572 if (csz.height() == -1) csz.setHeight(sz.height());
573 if (geo->maxWidth != -1 && csz.width() > geo->maxWidth) csz.setWidth(geo->maxWidth);
574 if (geo->maxHeight != -1 && csz.height() > geo->maxHeight) csz.setHeight(geo->maxHeight);
575 csz=csz.expandedTo(QSize(geo->minWidth, geo->minHeight));
576 return csz;
577 }
578
579 int features;
580 QBrush defaultBackground;
581 QFont font;
582 bool hasFont;
583
584 QHash<QString, QVariant> styleHints;
585 bool hasStyleHint(const QString& sh) const { return styleHints.contains(sh); }
586 QVariant styleHint(const QString& sh) const { return styleHints.value(sh); }
587
588 void fixupBorder(int);
589
590 QSharedDataPointer<QStyleSheetPaletteData> pal;
591 QSharedDataPointer<QStyleSheetBoxData> b;
592 QSharedDataPointer<QStyleSheetBackgroundData> bg;
593 QSharedDataPointer<QStyleSheetBorderData> bd;
594 QSharedDataPointer<QStyleSheetOutlineData> ou;
595 QSharedDataPointer<QStyleSheetGeometryData> geo;
596 QSharedDataPointer<QStyleSheetPositionData> p;
597 QSharedDataPointer<QStyleSheetImageData> img;
598
599 // Shouldn't be here
600 void setClip(QPainter *p, const QRect &rect);
601 void unsetClip(QPainter *);
602 int clipset;
603 QPainterPath clipPath;
604};
605
606///////////////////////////////////////////////////////////////////////////////////////////
607static const char *knownStyleHints[] = {
608 "activate-on-singleclick",
609 "alignment",
610 "arrow-keys-navigate-into-children",
611 "backward-icon",
612 "button-layout",
613 "cd-icon",
614 "combobox-list-mousetracking",
615 "combobox-popup",
616 "computer-icon",
617 "desktop-icon",
618 "dialog-apply-icon",
619 "dialog-cancel-icon",
620 "dialog-close-icon",
621 "dialog-discard-icon",
622 "dialog-help-icon",
623 "dialog-no-icon",
624 "dialog-ok-icon",
625 "dialog-open-icon",
626 "dialog-reset-icon",
627 "dialog-save-icon",
628 "dialog-yes-icon",
629 "dialogbuttonbox-buttons-have-icons",
630 "directory-closed-icon",
631 "directory-icon",
632 "directory-link-icon",
633 "directory-open-icon",
634 "dither-disable-text",
635 "dockwidget-close-icon",
636 "downarrow-icon",
637 "dvd-icon",
638 "etch-disabled-text",
639 "file-icon",
640 "file-link-icon",
641 "filedialog-backward-icon", // unused
642 "filedialog-contentsview-icon",
643 "filedialog-detailedview-icon",
644 "filedialog-end-icon",
645 "filedialog-infoview-icon",
646 "filedialog-listview-icon",
647 "filedialog-new-directory-icon",
648 "filedialog-parent-directory-icon",
649 "filedialog-start-icon",
650 "floppy-icon",
651 "forward-icon",
652 "gridline-color",
653 "harddisk-icon",
654 "home-icon",
655 "icon-size",
656 "leftarrow-icon",
657 "lineedit-password-character",
658 "mdi-fill-space-on-maximize",
659 "menu-scrollable",
660 "menubar-altkey-navigation",
661 "menubar-separator",
662 "messagebox-critical-icon",
663 "messagebox-information-icon",
664 "messagebox-question-icon",
665 "messagebox-text-interaction-flags",
666 "messagebox-warning-icon",
667 "mouse-tracking",
668 "network-icon",
669 "opacity",
670 "paint-alternating-row-colors-for-empty-area",
671 "rightarrow-icon",
672 "scrollbar-contextmenu",
673 "scrollbar-leftclick-absolute-position",
674 "scrollbar-middleclick-absolute-position",
675 "scrollbar-roll-between-buttons",
676 "scrollbar-scroll-when-pointer-leaves-control",
677 "scrollview-frame-around-contents",
678 "show-decoration-selected",
679 "spinbox-click-autorepeat-rate",
680 "spincontrol-disable-on-bounds",
681 "tabbar-elide-mode",
682 "tabbar-prefer-no-arrows",
683 "titlebar-close-icon",
684 "titlebar-contexthelp-icon",
685 "titlebar-maximize-icon",
686 "titlebar-menu-icon",
687 "titlebar-minimize-icon",
688 "titlebar-normal-icon",
689 "titlebar-shade-icon",
690 "titlebar-unshade-icon",
691 "toolbutton-popup-delay",
692 "trash-icon",
693 "uparrow-icon"
694};
695
696static const int numKnownStyleHints = sizeof(knownStyleHints)/sizeof(knownStyleHints[0]);
697
698static QList<QVariant> subControlLayout(const QString& layout)
699{
700 QList<QVariant> buttons;
701 for (int i = 0; i < layout.count(); i++) {
702 int button = layout[i].toAscii();
703 switch (button) {
704 case 'm':
705 buttons.append(PseudoElement_MdiMinButton);
706 buttons.append(PseudoElement_TitleBarMinButton);
707 break;
708 case 'M':
709 buttons.append(PseudoElement_TitleBarMaxButton);
710 break;
711 case 'X':
712 buttons.append(PseudoElement_MdiCloseButton);
713 buttons.append(PseudoElement_TitleBarCloseButton);
714 break;
715 case 'N':
716 buttons.append(PseudoElement_MdiNormalButton);
717 buttons.append(PseudoElement_TitleBarNormalButton);
718 break;
719 case 'I':
720 buttons.append(PseudoElement_TitleBarSysMenu);
721 break;
722 case 'T':
723 buttons.append(PseudoElement_TitleBar);
724 break;
725 case 'H':
726 buttons.append(PseudoElement_TitleBarContextHelpButton);
727 break;
728 case 'S':
729 buttons.append(PseudoElement_TitleBarShadeButton);
730 break;
731 default:
732 buttons.append(button);
733 break;
734 }
735 }
736 return buttons;
737}
738
739namespace {
740 struct ButtonInfo {
741 QRenderRule rule;
742 int element;
743 int offset;
744 int where;
745 int width;
746 };
747}
748
749QHash<QStyle::SubControl, QRect> QStyleSheetStyle::titleBarLayout(const QWidget *w, const QStyleOptionTitleBar *tb) const
750{
751 QHash<QStyle::SubControl, QRect> layoutRects;
752 const bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
753 const bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
754 QRenderRule subRule = renderRule(w, tb);
755 QRect cr = subRule.contentsRect(tb->rect);
756 QList<QVariant> layout = subRule.styleHint(QLatin1String("button-layout")).toList();
757 if (layout.isEmpty())
758 layout = subControlLayout(QLatin1String("I(T)HSmMX"));
759
760 int offsets[3] = { 0, 0, 0 };
761 enum Where { Left, Right, Center, NoWhere } where = Left;
762 QList<ButtonInfo> infos;
763 for (int i = 0; i < layout.count(); i++) {
764 ButtonInfo info;
765 info.element = layout[i].toInt();
766 if (info.element == '(') {
767 where = Center;
768 } else if (info.element == ')') {
769 where = Right;
770 } else {
771 switch (info.element) {
772 case PseudoElement_TitleBar:
773 if (!(tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)))
774 continue;
775 break;
776 case PseudoElement_TitleBarContextHelpButton:
777 if (!(tb->titleBarFlags & Qt::WindowContextHelpButtonHint))
778 continue;
779 break;
780 case PseudoElement_TitleBarMinButton:
781 if (!(tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
782 continue;
783 if (isMinimized)
784 info.element = PseudoElement_TitleBarNormalButton;
785 break;
786 case PseudoElement_TitleBarMaxButton:
787 if (!(tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
788 continue;
789 if (isMaximized)
790 info.element = PseudoElement_TitleBarNormalButton;
791 break;
792 case PseudoElement_TitleBarShadeButton:
793 if (!(tb->titleBarFlags & Qt::WindowShadeButtonHint))
794 continue;
795 if (isMinimized)
796 info.element = PseudoElement_TitleBarUnshadeButton;
797 break;
798 case PseudoElement_TitleBarCloseButton:
799 case PseudoElement_TitleBarSysMenu:
800 if (!(tb->titleBarFlags & Qt::WindowSystemMenuHint))
801 continue;
802 break;
803 default:
804 continue;
805 }
806 if (info.element == PseudoElement_TitleBar) {
807 info.width = tb->fontMetrics.width(tb->text) + 6;
808 subRule.geo = new QStyleSheetGeometryData(info.width, tb->fontMetrics.height(), -1, -1, -1, -1);
809 } else {
810 subRule = renderRule(w, tb, info.element);
811 info.width = subRule.size().width();
812 }
813 info.rule = subRule;
814 info.offset = offsets[where];
815 info.where = where;
816 infos.append(info);
817
818 offsets[where] += info.width;
819 }
820 }
821
822 for (int i = 0; i < infos.count(); i++) {
823 ButtonInfo info = infos[i];
824 QRect lr = cr;
825 switch (info.where) {
826 case Center: {
827 lr.setLeft(cr.left() + offsets[Left]);
828 lr.setRight(cr.right() - offsets[Right]);
829 QRect r(0, 0, offsets[Center], lr.height());
830 r.moveCenter(lr.center());
831 r.setLeft(r.left()+info.offset);
832 r.setWidth(info.width);
833 lr = r;
834 break; }
835 case Left:
836 lr.translate(info.offset, 0);
837 lr.setWidth(info.width);
838 break;
839 case Right:
840 lr.moveLeft(cr.right() + 1 - offsets[Right] + info.offset);
841 lr.setWidth(info.width);
842 break;
843 default:
844 break;
845 }
846 QStyle::SubControl control = knownPseudoElements[info.element].subControl;
847 layoutRects[control] = positionRect(w, info.rule, info.element, lr, tb->direction);
848 }
849
850 return layoutRects;
851}
852
853static QStyle::StandardPixmap subControlIcon(int pe)
854{
855 switch (pe) {
856 case PseudoElement_MdiCloseButton: return QStyle::SP_TitleBarCloseButton;
857 case PseudoElement_MdiMinButton: return QStyle::SP_TitleBarMinButton;
858 case PseudoElement_MdiNormalButton: return QStyle::SP_TitleBarNormalButton;
859 case PseudoElement_TitleBarCloseButton: return QStyle::SP_TitleBarCloseButton;
860 case PseudoElement_TitleBarMinButton: return QStyle::SP_TitleBarMinButton;
861 case PseudoElement_TitleBarMaxButton: return QStyle::SP_TitleBarMaxButton;
862 case PseudoElement_TitleBarShadeButton: return QStyle::SP_TitleBarShadeButton;
863 case PseudoElement_TitleBarUnshadeButton: return QStyle::SP_TitleBarUnshadeButton;
864 case PseudoElement_TitleBarNormalButton: return QStyle::SP_TitleBarNormalButton;
865 case PseudoElement_TitleBarContextHelpButton: return QStyle::SP_TitleBarContextHelpButton;
866 default: break;
867 }
868 return QStyle::SP_CustomBase;
869}
870
871QRenderRule::QRenderRule(const QVector<Declaration> &declarations, const QWidget *widget)
872: features(0), hasFont(false), pal(0), b(0), bg(0), bd(0), ou(0), geo(0), p(0), img(0), clipset(0)
873{
874 QPalette palette = qApp->palette(); // ###: ideally widget's palette
875 ValueExtractor v(declarations, palette);
876 features = v.extractStyleFeatures();
877
878 int w = -1, h = -1, minw = -1, minh = -1, maxw = -1, maxh = -1;
879 if (v.extractGeometry(&w, &h, &minw, &minh, &maxw, &maxh))
880 geo = new QStyleSheetGeometryData(w, h, minw, minh, maxw, maxh);
881
882 int left = 0, top = 0, right = 0, bottom = 0;
883 Origin origin = Origin_Unknown;
884 Qt::Alignment position = 0;
885 QCss::PositionMode mode = PositionMode_Unknown;
886 Qt::Alignment textAlignment = 0;
887 if (v.extractPosition(&left, &top, &right, &bottom, &origin, &position, &mode, &textAlignment))
888 p = new QStyleSheetPositionData(left, top, right, bottom, origin, position, mode, textAlignment);
889
890 int margins[4], paddings[4], spacing = -1;
891 for (int i = 0; i < 4; i++)
892 margins[i] = paddings[i] = 0;
893 if (v.extractBox(margins, paddings, &spacing))
894 b = new QStyleSheetBoxData(margins, paddings, spacing);
895
896 int borders[4];
897 QBrush colors[4];
898 QCss::BorderStyle styles[4];
899 QSize radii[4];
900 for (int i = 0; i < 4; i++) {
901 borders[i] = 0;
902 styles[i] = BorderStyle_None;
903 }
904 if (v.extractBorder(borders, colors, styles, radii))
905 bd = new QStyleSheetBorderData(borders, colors, styles, radii);
906
907 int offsets[4];
908 for (int i = 0; i < 4; i++) {
909 borders[i] = offsets[i] = 0;
910 styles[i] = BorderStyle_None;
911 }
912 if (v.extractOutline(borders, colors, styles, radii, offsets))
913 ou = new QStyleSheetOutlineData(borders, colors, styles, radii, offsets);
914
915 QBrush brush;
916 QString uri;
917 Repeat repeat = Repeat_XY;
918 Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft;
919 Attachment attachment = Attachment_Scroll;
920 origin = Origin_Padding;
921 Origin clip = Origin_Border;
922 if (v.extractBackground(&brush, &uri, &repeat, &alignment, &origin, &attachment, &clip))
923 bg = new QStyleSheetBackgroundData(brush, QPixmap(uri), repeat, alignment, origin, attachment, clip);
924
925 QBrush sfg, fg;
926 QBrush sbg, abg;
927 if (v.extractPalette(&fg, &sfg, &sbg, &abg))
928 pal = new QStyleSheetPaletteData(fg, sfg, sbg, abg);
929
930 QIcon icon;
931 alignment = Qt::AlignCenter;
932 QSize size;
933 if (v.extractImage(&icon, &alignment, &size))
934 img = new QStyleSheetImageData(icon, alignment, size);
935
936 int adj = -255;
937 hasFont = v.extractFont(&font, &adj);
938
939#ifndef QT_NO_TOOLTIP
940 if (widget && qstrcmp(widget->metaObject()->className(), "QTipLabel") == 0)
941 palette = QToolTip::palette();
942#endif
943
944 for (int i = 0; i < declarations.count(); i++) {
945 const Declaration& decl = declarations.at(i);
946 if (decl.d->propertyId == BorderImage) {
947 QString uri;
948 QCss::TileMode horizStretch, vertStretch;
949 int cuts[4];
950
951 decl.borderImageValue(&uri, cuts, &horizStretch, &vertStretch);
952 if (uri.isEmpty() || uri == QLatin1String("none")) {
953 if (bd && bd->bi)
954 bd->bi->pixmap = QPixmap();
955 } else {
956 if (!bd)
957 bd = new QStyleSheetBorderData;
958 if (!bd->bi)
959 bd->bi = new QStyleSheetBorderImageData;
960
961 QStyleSheetBorderImageData *bi = bd->bi;
962 bi->pixmap = QPixmap(uri);
963 for (int i = 0; i < 4; i++)
964 bi->cuts[i] = cuts[i];
965 bi->horizStretch = horizStretch;
966 bi->vertStretch = vertStretch;
967 }
968 } else if (decl.d->propertyId == QtBackgroundRole) {
969 if (bg && bg->brush.style() != Qt::NoBrush)
970 continue;
971 int role = decl.d->values.at(0).variant.toInt();
972 if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
973 defaultBackground = palette.color((QPalette::ColorRole)(role-Value_FirstColorRole));
974 } else if (decl.d->property.startsWith(QLatin1String("qproperty-"), Qt::CaseInsensitive)) {
975 // intentionally left blank...
976 } else if (decl.d->propertyId == UnknownProperty) {
977 bool knownStyleHint = false;
978 for (int i = 0; i < numKnownStyleHints; i++) {
979 QLatin1String styleHint(knownStyleHints[i]);
980 if (decl.d->property.compare(styleHint) == 0) {
981 QString hintName = QString(styleHint);
982 QVariant hintValue;
983 if (hintName.endsWith(QLatin1String("alignment"))) {
984 hintValue = (int) decl.alignmentValue();
985 } else if (hintName.endsWith(QLatin1String("color"))) {
986 hintValue = (int) decl.colorValue().rgba();
987 } else if (hintName.endsWith(QLatin1String("size"))) {
988 hintValue = decl.sizeValue();
989 } else if (hintName.endsWith(QLatin1String("icon"))) {
990 hintValue = decl.iconValue();
991 } else if (hintName == QLatin1String("button-layout")
992 && decl.d->values.count() != 0 && decl.d->values.at(0).type == Value::String) {
993 hintValue = subControlLayout(decl.d->values.at(0).variant.toString());
994 } else {
995 int integer;
996 decl.intValue(&integer);
997 hintValue = integer;
998 }
999 styleHints[decl.d->property] = hintValue;
1000 knownStyleHint = true;
1001 break;
1002 }
1003 }
1004 if (!knownStyleHint)
1005 qDebug("Unknown property %s", qPrintable(decl.d->property));
1006 }
1007 }
1008
1009 if (widget) {
1010 QStyleSheetStyle *style = const_cast<QStyleSheetStyle *>(globalStyleSheetStyle);
1011 if (!style)
1012 style = qobject_cast<QStyleSheetStyle *>(widget->style());
1013 if (style)
1014 fixupBorder(style->nativeFrameWidth(widget));
1015
1016 }
1017 if (hasBorder() && border()->hasBorderImage())
1018 defaultBackground = QBrush();
1019}
1020
1021QRect QRenderRule::borderRect(const QRect& r) const
1022{
1023 if (!hasBox())
1024 return r;
1025 const int* m = box()->margins;
1026 return r.adjusted(m[LeftEdge], m[TopEdge], -m[RightEdge], -m[BottomEdge]);
1027}
1028
1029QRect QRenderRule::outlineRect(const QRect& r) const
1030{
1031 QRect br = borderRect(r);
1032 if (!hasOutline())
1033 return br;
1034 const int *b = outline()->borders;
1035 return r.adjusted(b[LeftEdge], b[TopEdge], -b[RightEdge], -b[BottomEdge]);
1036}
1037
1038QRect QRenderRule::paddingRect(const QRect& r) const
1039{
1040 QRect br = borderRect(r);
1041 if (!hasBorder())
1042 return br;
1043 const int *b = border()->borders;
1044 return br.adjusted(b[LeftEdge], b[TopEdge], -b[RightEdge], -b[BottomEdge]);
1045}
1046
1047QRect QRenderRule::contentsRect(const QRect& r) const
1048{
1049 QRect pr = paddingRect(r);
1050 if (!hasBox())
1051 return pr;
1052 const int *p = box()->paddings;
1053 return pr.adjusted(p[LeftEdge], p[TopEdge], -p[RightEdge], -p[BottomEdge]);
1054}
1055
1056QRect QRenderRule::boxRect(const QRect& cr, int flags) const
1057{
1058 QRect r = cr;
1059 if (hasBox()) {
1060 if (flags & Margin) {
1061 const int *m = box()->margins;
1062 r.adjust(-m[LeftEdge], -m[TopEdge], m[RightEdge], m[BottomEdge]);
1063 }
1064 if (flags & Padding) {
1065 const int *p = box()->paddings;
1066 r.adjust(-p[LeftEdge], -p[TopEdge], p[RightEdge], p[BottomEdge]);
1067 }
1068 }
1069 if (!hasNativeBorder() && (flags & Border)) {
1070 const int *b = border()->borders;
1071 r.adjust(-b[LeftEdge], -b[TopEdge], b[RightEdge], b[BottomEdge]);
1072 }
1073 return r;
1074}
1075
1076QSize QRenderRule::boxSize(const QSize &cs, int flags) const
1077{
1078 QSize bs = boxRect(QRect(QPoint(0, 0), cs), flags).size();
1079 if (cs.width() < 0) bs.setWidth(-1);
1080 if (cs.height() < 0) bs.setHeight(-1);
1081 return bs;
1082}
1083
1084void QRenderRule::fixupBorder(int nativeWidth)
1085{
1086 if (bd == 0)
1087 return;
1088
1089 if (!bd->hasBorderImage() || bd->bi->pixmap.isNull()) {
1090 bd->bi = 0;
1091 // ignore the color, border of edges that have none border-style
1092 QBrush color = pal ? pal->foreground : QBrush();
1093 const bool hasRadius = bd->radii[0].isValid() || bd->radii[1].isValid()
1094 || bd->radii[2].isValid() || bd->radii[3].isValid();
1095 for (int i = 0; i < 4; i++) {
1096 if ((bd->styles[i] == BorderStyle_Native) && hasRadius)
1097 bd->styles[i] = BorderStyle_None;
1098
1099 switch (bd->styles[i]) {
1100 case BorderStyle_None:
1101 // border-style: none forces width to be 0
1102 bd->colors[i] = QBrush();
1103 bd->borders[i] = 0;
1104 break;
1105 case BorderStyle_Native:
1106 if (bd->borders[i] == 0)
1107 bd->borders[i] = nativeWidth;
1108 // intentional fall through
1109 default:
1110 if (!bd->colors[i].style() != Qt::NoBrush) // auto-acquire 'color'
1111 bd->colors[i] = color;
1112 break;
1113 }
1114 }
1115
1116 return;
1117 }
1118
1119 // inspect the border image
1120 QStyleSheetBorderImageData *bi = bd->bi;
1121 if (bi->cuts[0] == -1) {
1122 for (int i = 0; i < 4; i++) // assume, cut = border
1123 bi->cuts[i] = int(border()->borders[i]);
1124 }
1125 bi->cutBorderImage();
1126}
1127
1128void QStyleSheetBorderImageData::cutBorderImage()
1129{
1130 const int w = pixmap.width();
1131 const int h = pixmap.height();
1132 const int &l = cuts[LeftEdge], &r = cuts[RightEdge],
1133 &t = cuts[TopEdge], &b = cuts[BottomEdge];
1134
1135 topEdgeRect = QRect(l, 0, w - r - l, t);
1136 bottomEdgeRect = QRect(l, h - b, w - l - r, b);
1137 if (horizStretch != TileMode_Stretch) {
1138 if (topEdgeRect.isValid())
1139 topEdge = pixmap.copy(topEdgeRect).scaledToHeight(t);
1140 if (bottomEdgeRect.isValid())
1141 bottomEdge = pixmap.copy(bottomEdgeRect).scaledToHeight(b);
1142 }
1143
1144 leftEdgeRect = QRect(0, t, l, h - b - t);
1145 rightEdgeRect = QRect(w - r, t, r, h - t- b);
1146 if (vertStretch != TileMode_Stretch) {
1147 if (leftEdgeRect.isValid())
1148 leftEdge = pixmap.copy(leftEdgeRect).scaledToWidth(l);
1149 if (rightEdgeRect.isValid())
1150 rightEdge = pixmap.copy(rightEdgeRect).scaledToWidth(r);
1151 }
1152
1153 middleRect = QRect(l, t, w - r -l, h - t - b);
1154 if (middleRect.isValid()
1155 && !(horizStretch == TileMode_Stretch && vertStretch == TileMode_Stretch)) {
1156 middle = pixmap.copy(middleRect);
1157 }
1158}
1159
1160static void qDrawCenterTiledPixmap(QPainter *p, const QRectF& r, const QPixmap& pix)
1161{
1162 p->drawTiledPixmap(r, pix, QPoint(pix.width() - int(r.width())%pix.width(),
1163 pix.height() - int(r.height())%pix.height()));
1164}
1165
1166// Note: Round is not supported
1167void QRenderRule::drawBorderImage(QPainter *p, const QRect& rect)
1168{
1169 setClip(p, rect);
1170 const QRectF br(rect);
1171 const int *borders = border()->borders;
1172 const int &l = borders[LeftEdge], &r = borders[RightEdge],
1173 &t = borders[TopEdge], &b = borders[BottomEdge];
1174 QRectF pr = br.adjusted(l, t, -r, -b);
1175
1176 bool wasSmoothPixmapTransform = p->renderHints() & QPainter::SmoothPixmapTransform;
1177 p->setRenderHint(QPainter::SmoothPixmapTransform);
1178
1179 const QStyleSheetBorderImageData *bi = border()->borderImage();
1180 const QPixmap& pix = bi->pixmap;
1181 const int *c = bi->cuts;
1182 QRectF tlc(0, 0, c[LeftEdge], c[TopEdge]);
1183 if (tlc.isValid())
1184 p->drawPixmap(QRectF(br.topLeft(), QSizeF(l, t)), pix, tlc);
1185 QRectF trc(pix.width() - c[RightEdge], 0, c[RightEdge], c[TopEdge]);
1186 if (trc.isValid())
1187 p->drawPixmap(QRectF(br.left() + br.width() - r, br.y(), r, t), pix, trc);
1188 QRectF blc(0, pix.height() - c[BottomEdge], c[LeftEdge], c[BottomEdge]);
1189 if (blc.isValid())
1190 p->drawPixmap(QRectF(br.x(), br.y() + br.height() - b, l, b), pix, blc);
1191 QRectF brc(pix.width() - c[RightEdge], pix.height() - c[BottomEdge],
1192 c[RightEdge], c[BottomEdge]);
1193 if (brc.isValid())
1194 p->drawPixmap(QRectF(br.x() + br.width() - r, br.y() + br.height() - b, r, b),
1195 pix, brc);
1196
1197 QRectF topEdgeRect(br.x() + l, br.y(), pr.width(), t);
1198 QRectF bottomEdgeRect(br.x() + l, br.y() + br.height() - b, pr.width(), b);
1199
1200 switch (bi->horizStretch) {
1201 case TileMode_Stretch:
1202 if (bi->topEdgeRect.isValid())
1203 p->drawPixmap(topEdgeRect, pix, bi->topEdgeRect);
1204 if (bi->bottomEdgeRect.isValid())
1205 p->drawPixmap(bottomEdgeRect, pix, bi->bottomEdgeRect);
1206 if (bi->middleRect.isValid()) {
1207 if (bi->vertStretch == TileMode_Stretch)
1208 p->drawPixmap(pr, pix, bi->middleRect);
1209 else if (bi->vertStretch == TileMode_Repeat) {
1210 QPixmap scaled = bi->middle.scaled(int(pr.width()), bi->middle.height());
1211 qDrawCenterTiledPixmap(p, pr, scaled);
1212 }
1213 }
1214 break;
1215 case TileMode_Repeat:
1216 if (!bi->topEdge.isNull() && !topEdgeRect.isEmpty()) {
1217 QPixmap scaled = bi->topEdge.scaled(bi->topEdge.width(), t);
1218 qDrawCenterTiledPixmap(p, topEdgeRect, scaled);
1219 }
1220 if (!bi->bottomEdge.isNull() && !bottomEdgeRect.isEmpty()) {
1221 QPixmap scaled = bi->bottomEdge.scaled(bi->bottomEdge.width(), b);
1222 qDrawCenterTiledPixmap(p, bottomEdgeRect, scaled);
1223 }
1224 if (bi->middleRect.isValid()) {
1225 if (bi->vertStretch == TileMode_Repeat) {
1226 qDrawCenterTiledPixmap(p, pr, bi->middle);
1227 } else if (bi->vertStretch == TileMode_Stretch) {
1228 QPixmap scaled = bi->middle.scaled(bi->middle.width(), int(pr.height()));
1229 qDrawCenterTiledPixmap(p, pr, scaled);
1230 }
1231 }
1232 break;
1233 case TileMode_Round:
1234 if (!bi->topEdge.isNull()) {
1235 int rwh = (int)pr.width()/ceil(pr.width()/bi->topEdge.width());
1236 QPixmap scaled = bi->topEdge.scaled(rwh, bi->topEdge.height());
1237 int blank = int(pr.width()) % rwh;
1238 p->drawTiledPixmap(QRectF(br.x() + l + blank/2, br.y(), pr.width() - blank, t),
1239 scaled);
1240 }
1241 if (!bi->bottomEdge.isNull()) {
1242 int rwh = (int) pr.width()/ceil(pr.width()/bi->bottomEdge.width());
1243 QPixmap scaled = bi->bottomEdge.scaled(rwh, bi->bottomEdge.height());
1244 int blank = int(pr.width()) % rwh;
1245 p->drawTiledPixmap(QRectF(br.x() + l+ blank/2, br.y()+br.height()-b,
1246 pr.width() - blank, b), scaled);
1247 }
1248 break;
1249 default:
1250 break;
1251 }
1252
1253 QRectF leftEdgeRect(br.x(), br.y() + t, l, pr.height());
1254 QRectF rightEdgeRect(br.x() + br.width()- r, br.y() + t, r, pr.height());
1255
1256 switch (bi->vertStretch) {
1257 case TileMode_Stretch:
1258 if (bi->leftEdgeRect.isValid())
1259 p->drawPixmap(leftEdgeRect, pix, bi->leftEdgeRect);
1260 if (bi->rightEdgeRect.isValid())
1261 p->drawPixmap(rightEdgeRect, pix, bi->rightEdgeRect);
1262 break;
1263 case TileMode_Repeat:
1264 if (!bi->leftEdge.isNull() && !leftEdgeRect.isEmpty()) {
1265 QPixmap scaled = bi->leftEdge.scaled(l, bi->leftEdge.height());
1266 qDrawCenterTiledPixmap(p, leftEdgeRect, scaled);
1267 }
1268 if (!bi->rightEdge.isNull() && !rightEdgeRect.isEmpty()) {
1269 QPixmap scaled = bi->rightEdge.scaled(r, bi->rightEdge.height());
1270 qDrawCenterTiledPixmap(p, rightEdgeRect, scaled);
1271 }
1272 break;
1273 case TileMode_Round:
1274 if (!bi->leftEdge.isNull()) {
1275 int rwh = (int) pr.height()/ceil(pr.height()/bi->leftEdge.height());
1276 QPixmap scaled = bi->leftEdge.scaled(bi->leftEdge.width(), rwh);
1277 int blank = int(pr.height()) % rwh;
1278 p->drawTiledPixmap(QRectF(br.x(), br.y() + t + blank/2, l, pr.height() - blank),
1279 scaled);
1280 }
1281 if (!bi->rightEdge.isNull()) {
1282 int rwh = (int) pr.height()/ceil(pr.height()/bi->rightEdge.height());
1283 QPixmap scaled = bi->rightEdge.scaled(bi->rightEdge.width(), rwh);
1284 int blank = int(pr.height()) % rwh;
1285 p->drawTiledPixmap(QRectF(br.x() + br.width() - r, br.y()+t+blank/2, r,
1286 pr.height() - blank), scaled);
1287 }
1288 break;
1289 default:
1290 break;
1291 }
1292
1293 p->setRenderHint(QPainter::SmoothPixmapTransform, wasSmoothPixmapTransform);
1294 unsetClip(p);
1295}
1296
1297QRect QRenderRule::originRect(const QRect &rect, Origin origin) const
1298{
1299 switch (origin) {
1300 case Origin_Padding:
1301 return paddingRect(rect);
1302 case Origin_Border:
1303 return borderRect(rect);
1304 case Origin_Content:
1305 return contentsRect(rect);
1306 case Origin_Margin:
1307 default:
1308 return rect;
1309 }
1310}
1311
1312void QRenderRule::drawBackgroundImage(QPainter *p, const QRect &rect, QPoint off)
1313{
1314 if (!hasBackground())
1315 return;
1316
1317 const QPixmap& bgp = background()->pixmap;
1318 if (bgp.isNull())
1319 return;
1320
1321 setClip(p, borderRect(rect));
1322
1323 if (background()->origin != background()->clip) {
1324 p->save();
1325 p->setClipRect(originRect(rect, background()->clip), Qt::IntersectClip);
1326 }
1327
1328 if (background()->attachment == Attachment_Fixed)
1329 off = QPoint(0, 0);
1330
1331 QRect r = originRect(rect, background()->origin);
1332 QRect aligned = QStyle::alignedRect(Qt::LeftToRight, background()->position, bgp.size(), r);
1333 QRect inter = aligned.intersected(r);
1334
1335 switch (background()->repeat) {
1336 case Repeat_Y:
1337 p->drawTiledPixmap(inter.x(), r.y(), inter.width(), r.height(), bgp,
1338 inter.x() - aligned.x() + off.x(),
1339 bgp.height() - int(aligned.y() - r.y()) % bgp.height() + off.y());
1340 break;
1341 case Repeat_X:
1342 p->drawTiledPixmap(r.x(), inter.y(), r.width(), inter.height(), bgp,
1343 bgp.width() - int(aligned.x() - r.x())%bgp.width() + off.x(),
1344 inter.y() - aligned.y() + off.y());
1345 break;
1346 case Repeat_XY:
1347 p->drawTiledPixmap(r, bgp,
1348 QPoint(bgp.width() - int(aligned.x() - r.x())% bgp.width() + off.x(),
1349 bgp.height() - int(aligned.y() - r.y())%bgp.height() + off.y()));
1350 break;
1351 case Repeat_None:
1352 default:
1353 p->drawPixmap(inter.x(), inter.y(), bgp, inter.x() - aligned.x() + off.x(),
1354 inter.y() - aligned.y() + off.y(), inter.width(), inter.height());
1355 break;
1356 }
1357
1358
1359 if (background()->origin != background()->clip)
1360 p->restore();
1361
1362 unsetClip(p);
1363}
1364
1365void QRenderRule::drawOutline(QPainter *p, const QRect &rect)
1366{
1367 if (!hasOutline())
1368 return;
1369
1370 bool wasAntialiased = p->renderHints() & QPainter::Antialiasing;
1371 p->setRenderHint(QPainter::Antialiasing);
1372 qDrawBorder(p, rect, ou->styles, ou->borders, ou->colors, ou->radii);
1373 p->setRenderHint(QPainter::Antialiasing, wasAntialiased);
1374}
1375
1376void QRenderRule::drawBorder(QPainter *p, const QRect& rect)
1377{
1378 if (!hasBorder())
1379 return;
1380
1381 if (border()->hasBorderImage()) {
1382 drawBorderImage(p, rect);
1383 return;
1384 }
1385
1386 bool wasAntialiased = p->renderHints() & QPainter::Antialiasing;
1387 p->setRenderHint(QPainter::Antialiasing);
1388 qDrawBorder(p, rect, bd->styles, bd->borders, bd->colors, bd->radii);
1389 p->setRenderHint(QPainter::Antialiasing, wasAntialiased);
1390}
1391
1392QPainterPath QRenderRule::borderClip(QRect r)
1393{
1394 if (!hasBorder())
1395 return QPainterPath();
1396
1397 QSize tlr, trr, blr, brr;
1398 qNormalizeRadii(r, bd->radii, &tlr, &trr, &blr, &brr);
1399 if (tlr.isNull() && trr.isNull() && blr.isNull() && brr.isNull())
1400 return QPainterPath();
1401
1402 const QRectF rect(r);
1403 const int *borders = border()->borders;
1404 QPainterPath path;
1405 qreal curY = rect.y() + borders[TopEdge]/2.0;
1406 path.moveTo(rect.x() + tlr.width(), curY);
1407 path.lineTo(rect.right() - trr.width(), curY);
1408 qreal curX = rect.right() - borders[RightEdge]/2.0;
1409 path.arcTo(curX - 2*trr.width() + borders[RightEdge], curY,
1410 trr.width()*2 - borders[RightEdge], trr.height()*2 - borders[TopEdge], 90, -90);
1411
1412 path.lineTo(curX, rect.bottom() - brr.height());
1413 curY = rect.bottom() - borders[BottomEdge]/2.0;
1414 path.arcTo(curX - 2*brr.width() + borders[RightEdge], curY - 2*brr.height() + borders[BottomEdge],
1415 brr.width()*2 - borders[RightEdge], brr.height()*2 - borders[BottomEdge], 0, -90);
1416
1417 path.lineTo(rect.x() + blr.width(), curY);
1418 curX = rect.left() + borders[LeftEdge]/2.0;
1419 path.arcTo(curX, rect.bottom() - 2*blr.height() + borders[BottomEdge]/2,
1420 blr.width()*2 - borders[LeftEdge], blr.height()*2 - borders[BottomEdge], 270, -90);
1421
1422 path.lineTo(curX, rect.top() + tlr.height());
1423 path.arcTo(curX, rect.top() + borders[TopEdge]/2,
1424 tlr.width()*2 - borders[LeftEdge], tlr.height()*2 - borders[TopEdge], 180, -90);
1425
1426 path.closeSubpath();
1427 return path;
1428}
1429
1430/*! \internal
1431 Clip the painter to the border (in case we are using radius border)
1432 */
1433void QRenderRule::setClip(QPainter *p, const QRect &rect)
1434{
1435 if (clipset++)
1436 return;
1437 clipPath = borderClip(rect);
1438 if (!clipPath.isEmpty()) {
1439 p->save();
1440 p->setClipPath(clipPath, Qt::IntersectClip);
1441 }
1442}
1443
1444void QRenderRule::unsetClip(QPainter *p)
1445{
1446 if (--clipset)
1447 return;
1448 if (!clipPath.isEmpty())
1449 p->restore();
1450}
1451
1452void QRenderRule::drawBackground(QPainter *p, const QRect& rect, const QPoint& off)
1453{
1454 setClip(p, borderRect(rect));
1455 QBrush brush = hasBackground() ? background()->brush : QBrush();
1456 if (brush.style() == Qt::NoBrush)
1457 brush = defaultBackground;
1458
1459 if (brush.style() != Qt::NoBrush) {
1460 Origin origin = hasBackground() ? background()->clip : Origin_Border;
1461 // ### fix for gradients
1462 p->fillRect(originRect(rect, origin), brush);
1463 }
1464
1465 drawBackgroundImage(p, rect, off);
1466 unsetClip(p);
1467}
1468
1469void QRenderRule::drawFrame(QPainter *p, const QRect& rect)
1470{
1471 drawBackground(p, rect);
1472 if (hasBorder())
1473 drawBorder(p, borderRect(rect));
1474}
1475
1476void QRenderRule::drawImage(QPainter *p, const QRect &rect)
1477{
1478 if (!hasImage())
1479 return;
1480 img->icon.paint(p, rect, img->alignment);
1481}
1482
1483void QRenderRule::drawRule(QPainter *p, const QRect& rect)
1484{
1485 drawFrame(p, rect);
1486 drawImage(p, contentsRect(rect));
1487}
1488
1489// *shudder* , *horror*, *whoa* <-- what you might feel when you see the functions below
1490void QRenderRule::configurePalette(QPalette *p, QPalette::ColorRole fr, QPalette::ColorRole br)
1491{
1492 if (bg && bg->brush.style() != Qt::NoBrush) {
1493 if (br != QPalette::NoRole)
1494 p->setBrush(br, bg->brush);
1495 p->setBrush(QPalette::Window, bg->brush);
1496 }
1497
1498 if (!hasPalette())
1499 return;
1500
1501 if (pal->foreground.style() != Qt::NoBrush) {
1502 if (fr != QPalette::NoRole)
1503 p->setBrush(fr, pal->foreground);
1504 p->setBrush(QPalette::WindowText, pal->foreground);
1505 p->setBrush(QPalette::Text, pal->foreground);
1506 }
1507 if (pal->selectionBackground.style() != Qt::NoBrush)
1508 p->setBrush(QPalette::Highlight, pal->selectionBackground);
1509 if (pal->selectionForeground.style() != Qt::NoBrush)
1510 p->setBrush(QPalette::HighlightedText, pal->selectionForeground);
1511 if (pal->alternateBackground.style() != Qt::NoBrush)
1512 p->setBrush(QPalette::AlternateBase, pal->alternateBackground);
1513}
1514
1515void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const QWidget *w, bool embedded)
1516{
1517 if (bg && bg->brush.style() != Qt::NoBrush) {
1518 p->setBrush(cg, QPalette::Base, bg->brush); // for windows, windowxp
1519 p->setBrush(cg, QPalette::Button, bg->brush); // for plastique
1520 p->setBrush(cg, w->backgroundRole(), bg->brush);
1521 p->setBrush(cg, QPalette::Window, bg->brush);
1522 }
1523
1524 if (embedded) {
1525 /* For embedded widgets (ComboBox, SpinBox and ScrollArea) we want the embedded widget
1526 * to be transparent when we have a transparent background or border image */
1527 if ((hasBackground() && background()->isTransparent())
1528 || (hasBorder() && border()->hasBorderImage() && border()->borderImage()->middleRect.isValid()))
1529 p->setBrush(cg, w->backgroundRole(), Qt::NoBrush);
1530 }
1531
1532 if (!hasPalette())
1533 return;
1534
1535 if (pal->foreground.style() != Qt::NoBrush) {
1536 p->setBrush(cg, QPalette::ButtonText, pal->foreground);
1537 p->setBrush(cg, w->foregroundRole(), pal->foreground);
1538 p->setBrush(cg, QPalette::WindowText, pal->foreground);
1539 p->setBrush(cg, QPalette::Text, pal->foreground);
1540 }
1541 if (pal->selectionBackground.style() != Qt::NoBrush)
1542 p->setBrush(cg, QPalette::Highlight, pal->selectionBackground);
1543 if (pal->selectionForeground.style() != Qt::NoBrush)
1544 p->setBrush(cg, QPalette::HighlightedText, pal->selectionForeground);
1545 if (pal->alternateBackground.style() != Qt::NoBrush)
1546 p->setBrush(cg, QPalette::AlternateBase, pal->alternateBackground);
1547}
1548
1549///////////////////////////////////////////////////////////////////////////////
1550// Style rules
1551#define WIDGET(x) (static_cast<QWidget *>(x.ptr))
1552
1553static inline QWidget *parentWidget(const QWidget *w)
1554{
1555 if(qobject_cast<const QLabel *>(w) && qstrcmp(w->metaObject()->className(), "QTipLabel") == 0) {
1556 QWidget *p = qvariant_cast<QWidget *>(w->property("_q_stylesheet_parent"));
1557 if (p)
1558 return p;
1559 }
1560 return w->parentWidget();
1561}
1562
1563class QStyleSheetStyleSelector : public StyleSelector
1564{
1565public:
1566 QStyleSheetStyleSelector() { }
1567
1568 QStringList nodeNames(NodePtr node) const
1569 {
1570 if (isNullNode(node))
1571 return QStringList();
1572 const QMetaObject *metaObject = WIDGET(node)->metaObject();
1573#ifndef QT_NO_TOOLTIP
1574 if (qstrcmp(metaObject->className(), "QTipLabel") == 0)
1575 return QStringList(QLatin1String("QToolTip"));
1576#endif
1577 QStringList result;
1578 do {
1579 result += QString::fromLatin1(metaObject->className()).replace(QLatin1Char(':'), QLatin1Char('-'));
1580 metaObject = metaObject->superClass();
1581 } while (metaObject != 0);
1582 return result;
1583 }
1584 QString attribute(NodePtr node, const QString& name) const
1585 {
1586 if (isNullNode(node))
1587 return QString();
1588
1589 QHash<QString, QString> &cache = m_attributeCache[WIDGET(node)];
1590 QHash<QString, QString>::const_iterator cacheIt = cache.constFind(name);
1591 if (cacheIt != cache.constEnd())
1592 return cacheIt.value();
1593
1594 QVariant value = WIDGET(node)->property(name.toLatin1());
1595 if (!value.isValid()) {
1596 if (name == QLatin1String("class")) {
1597 QString className = QString::fromLatin1(WIDGET(node)->metaObject()->className());
1598 if (className.contains(QLatin1Char(':')))
1599 className.replace(QLatin1Char(':'), QLatin1Char('-'));
1600 cache[name] = className;
1601 return className;
1602 } else if (name == QLatin1String("style")) {
1603 QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle *>(WIDGET(node)->style());
1604 if (proxy) {
1605 QString styleName = QString::fromLatin1(proxy->baseStyle()->metaObject()->className());
1606 cache[name] = styleName;
1607 return styleName;
1608 }
1609 }
1610 }
1611 QString valueStr;
1612 if(value.type() == QVariant::StringList || value.type() == QVariant::List)
1613 valueStr = value.toStringList().join(QLatin1String(" "));
1614 else
1615 valueStr = value.toString();
1616 cache[name] = valueStr;
1617 return valueStr;
1618 }
1619 bool nodeNameEquals(NodePtr node, const QString& nodeName) const
1620 {
1621 if (isNullNode(node))
1622 return false;
1623 const QMetaObject *metaObject = WIDGET(node)->metaObject();
1624#ifndef QT_NO_TOOLTIP
1625 if (qstrcmp(metaObject->className(), "QTipLabel") == 0)
1626 return nodeName == QLatin1String("QToolTip");
1627#endif
1628 do {
1629 const ushort *uc = (const ushort *)nodeName.constData();
1630 const ushort *e = uc + nodeName.length();
1631 const uchar *c = (uchar *)metaObject->className();
1632 while (*c && uc != e && (*uc == *c || (*c == ':' && *uc == '-'))) {
1633 ++uc;
1634 ++c;
1635 }
1636 if (uc == e && !*c)
1637 return true;
1638 metaObject = metaObject->superClass();
1639 } while (metaObject != 0);
1640 return false;
1641 }
1642 bool hasAttributes(NodePtr) const
1643 { return true; }
1644 QStringList nodeIds(NodePtr node) const
1645 { return isNullNode(node) ? QStringList() : QStringList(WIDGET(node)->objectName()); }
1646 bool isNullNode(NodePtr node) const
1647 { return node.ptr == 0; }
1648 NodePtr parentNode(NodePtr node) const
1649 { NodePtr n; n.ptr = isNullNode(node) ? 0 : parentWidget(WIDGET(node)); return n; }
1650 NodePtr previousSiblingNode(NodePtr) const
1651 { NodePtr n; n.ptr = 0; return n; }
1652 NodePtr duplicateNode(NodePtr node) const
1653 { return node; }
1654 void freeNode(NodePtr) const
1655 { }
1656
1657private:
1658 mutable QHash<const QWidget *, QHash<QString, QString> > m_attributeCache;
1659};
1660
1661QVector<QCss::StyleRule> QStyleSheetStyle::styleRules(const QWidget *w) const
1662{
1663 QHash<const QWidget *, QVector<StyleRule> >::const_iterator cacheIt = styleRulesCache->constFind(w);
1664 if (cacheIt != styleRulesCache->constEnd())
1665 return cacheIt.value();
1666
1667 if (!initWidget(w)) {
1668 return QVector<StyleRule>();
1669 }
1670
1671 QStyleSheetStyleSelector styleSelector;
1672
1673 StyleSheet defaultSs;
1674 QHash<const void *, StyleSheet>::const_iterator defaultCacheIt = styleSheetCache->constFind(baseStyle());
1675 if (defaultCacheIt == styleSheetCache->constEnd()) {
1676 defaultSs = getDefaultStyleSheet();
1677 styleSheetCache->insert(baseStyle(), defaultSs);
1678 } else {
1679 defaultSs = defaultCacheIt.value();
1680 }
1681 styleSelector.styleSheets += defaultSs;
1682
1683 if (!qApp->styleSheet().isEmpty()) {
1684 StyleSheet appSs;
1685 QHash<const void *, StyleSheet>::const_iterator appCacheIt = styleSheetCache->constFind(qApp);
1686 if (appCacheIt == styleSheetCache->constEnd()) {
1687 QString ss = qApp->styleSheet();
1688 if (ss.startsWith(QLatin1String("file:///")))
1689 ss.remove(0, 8);
1690 parser.init(ss, qApp->styleSheet() != ss);
1691 if (!parser.parse(&appSs))
1692 qWarning("Could not parse application stylesheet");
1693 appSs.origin = StyleSheetOrigin_Inline;
1694 appSs.depth = 1;
1695 styleSheetCache->insert(qApp, appSs);
1696 } else {
1697 appSs = appCacheIt.value();
1698 }
1699 styleSelector.styleSheets += appSs;
1700 }
1701
1702 QVector<QCss::StyleSheet> widgetSs;
1703 for (const QWidget *wid = w; wid; wid = parentWidget(wid)) {
1704 if (wid->styleSheet().isEmpty())
1705 continue;
1706 StyleSheet ss;
1707 QHash<const void *, StyleSheet>::const_iterator widCacheIt = styleSheetCache->constFind(wid);
1708 if (widCacheIt == styleSheetCache->constEnd()) {
1709 parser.init(wid->styleSheet());
1710 if (!parser.parse(&ss)) {
1711 parser.init(QLatin1String("* {") + wid->styleSheet() + QLatin1String("}"));
1712 if (!parser.parse(&ss))
1713 qWarning("Could not parse stylesheet of widget %p", wid);
1714 }
1715 ss.origin = StyleSheetOrigin_Inline;
1716 styleSheetCache->insert(wid, ss);
1717 } else {
1718 ss = widCacheIt.value();
1719 }
1720 widgetSs.append(ss);
1721 }
1722
1723 for (int i = 0; i < widgetSs.count(); i++)
1724 widgetSs[i].depth = widgetSs.count() - i + 2;
1725
1726 styleSelector.styleSheets += widgetSs;
1727
1728 StyleSelector::NodePtr n;
1729 n.ptr = (void *)w;
1730 QVector<QCss::StyleRule> rules = styleSelector.styleRulesForNode(n);
1731 styleRulesCache->insert(w, rules);
1732 return rules;
1733}
1734
1735/////////////////////////////////////////////////////////////////////////////////////////
1736// Rendering rules
1737static QVector<Declaration> declarations(const QVector<StyleRule> &styleRules, const QString &part, quint64 pseudoClass = PseudoClass_Unspecified)
1738{
1739 QVector<Declaration> decls;
1740 for (int i = 0; i < styleRules.count(); i++) {
1741 const Selector& selector = styleRules.at(i).selectors.at(0);
1742 // Rules with pseudo elements don't cascade. This is an intentional
1743 // diversion for CSS
1744 if (part.compare(selector.pseudoElement(), Qt::CaseInsensitive) != 0)
1745 continue;
1746 quint64 negated = 0;
1747 quint64 cssClass = selector.pseudoClass(&negated);
1748 if ((pseudoClass == PseudoClass_Any) || (cssClass == PseudoClass_Unspecified)
1749 || ((((cssClass & pseudoClass) == cssClass)) && ((negated & pseudoClass) == 0)))
1750 decls += styleRules.at(i).declarations;
1751 }
1752 return decls;
1753}
1754
1755int QStyleSheetStyle::nativeFrameWidth(const QWidget *w)
1756{
1757 QStyle *base = baseStyle();
1758
1759#ifndef QT_NO_SPINBOX
1760 if (qobject_cast<const QAbstractSpinBox *>(w))
1761 return base->pixelMetric(QStyle::PM_SpinBoxFrameWidth, 0, w);
1762#endif
1763
1764#ifndef QT_NO_COMBOBOX
1765 if (qobject_cast<const QComboBox *>(w))
1766 return base->pixelMetric(QStyle::PM_ComboBoxFrameWidth, 0, w);
1767#endif
1768
1769#ifndef QT_NO_MENU
1770 if (qobject_cast<const QMenu *>(w))
1771 return base->pixelMetric(QStyle::PM_MenuPanelWidth, 0, w);
1772#endif
1773
1774#ifndef QT_NO_MENUBAR
1775 if (qobject_cast<const QMenuBar *>(w))
1776 return base->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, w);
1777#endif
1778#ifndef QT_NO_FRAME
1779 if (const QFrame *frame = qobject_cast<const QFrame *>(w)) {
1780 if (frame->frameShape() == QFrame::NoFrame)
1781 return 0;
1782 }
1783#endif
1784
1785 if (qstrcmp(w->metaObject()->className(), "QTipLabel") == 0)
1786 return base->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0, w);
1787
1788 return base->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, w);
1789}
1790
1791static quint64 pseudoClass(QStyle::State state)
1792{
1793 quint64 pc = 0;
1794 if (state & QStyle::State_Enabled) {
1795 pc |= PseudoClass_Enabled;
1796 if (state & QStyle::State_MouseOver)
1797 pc |= PseudoClass_Hover;
1798 } else {
1799 pc |= PseudoClass_Disabled;
1800 }
1801 if (state & QStyle::State_Active)
1802 pc |= PseudoClass_Active;
1803 if (state & QStyle::State_Window)
1804 pc |= PseudoClass_Window;
1805 if (state & QStyle::State_Sunken)
1806 pc |= PseudoClass_Pressed;
1807 if (state & QStyle::State_HasFocus)
1808 pc |= PseudoClass_Focus;
1809 if (state & QStyle::State_On)
1810 pc |= (PseudoClass_On | PseudoClass_Checked);
1811 if (state & QStyle::State_Off)
1812 pc |= (PseudoClass_Off | PseudoClass_Unchecked);
1813 if (state & QStyle::State_NoChange)
1814 pc |= PseudoClass_Indeterminate;
1815 if (state & QStyle::State_Selected)
1816 pc |= PseudoClass_Selected;
1817 if (state & QStyle::State_Horizontal)
1818 pc |= PseudoClass_Horizontal;
1819 else
1820 pc |= PseudoClass_Vertical;
1821 if (state & (QStyle::State_Open | QStyle::State_On | QStyle::State_Sunken))
1822 pc |= PseudoClass_Open;
1823 else
1824 pc |= PseudoClass_Closed;
1825 if (state & QStyle::State_Children)
1826 pc |= PseudoClass_Children;
1827 if (state & QStyle::State_Sibling)
1828 pc |= PseudoClass_Sibling;
1829 if (state & QStyle::State_ReadOnly)
1830 pc |= PseudoClass_ReadOnly;
1831 if (state & QStyle::State_Item)
1832 pc |= PseudoClass_Item;
1833#ifdef QT_KEYPAD_NAVIGATION
1834 if (state & QStyle::State_HasEditFocus)
1835 pc |= PseudoClass_EditFocus;
1836#endif
1837 return pc;
1838}
1839
1840static void qt_check_if_internal_widget(const QWidget **w, int *element)
1841{
1842#ifdef QT_NO_DOCKWIDGET
1843 Q_UNUSED(w);
1844 Q_UNUSED(element);
1845#else
1846 if (*w && qstrcmp((*w)->metaObject()->className(), "QDockWidgetTitleButton") == 0) {
1847 if ((*w)->objectName() == QLatin1String("qt_dockwidget_closebutton")) {
1848 *element = PseudoElement_DockWidgetCloseButton;
1849 } else if ((*w)->objectName() == QLatin1String("qt_dockwidget_floatbutton")) {
1850 *element = PseudoElement_DockWidgetFloatButton;
1851 }
1852 *w = (*w)->parentWidget();
1853 }
1854#endif
1855}
1856
1857QRenderRule QStyleSheetStyle::renderRule(const QWidget *w, int element, quint64 state) const
1858{
1859 qt_check_if_internal_widget(&w, &element);
1860 QHash<quint64, QRenderRule> &cache = (*renderRulesCache)[w][element];
1861 QHash<quint64, QRenderRule>::const_iterator cacheIt = cache.constFind(state);
1862 if (cacheIt != cache.constEnd())
1863 return cacheIt.value();
1864
1865 if (!initWidget(w))
1866 return QRenderRule();
1867
1868 quint64 stateMask = 0;
1869 const QVector<StyleRule> rules = styleRules(w);
1870 for (int i = 0; i < rules.count(); i++) {
1871 const Selector& selector = rules.at(i).selectors.at(0);
1872 quint64 negated = 0;
1873 stateMask |= selector.pseudoClass(&negated);
1874 stateMask |= negated;
1875 }
1876
1877 cacheIt = cache.constFind(state & stateMask);
1878 if (cacheIt != cache.constEnd()) {
1879 const QRenderRule &newRule = cacheIt.value();
1880 cache[state] = newRule;
1881 return newRule;
1882 }
1883
1884
1885 const QString part = QLatin1String(knownPseudoElements[element].name);
1886 QVector<Declaration> decls = declarations(rules, part, state);
1887 QRenderRule newRule(decls, w);
1888 cache[state] = newRule;
1889 if ((state & stateMask) != state)
1890 cache[state&stateMask] = newRule;
1891 return newRule;
1892}
1893
1894QRenderRule QStyleSheetStyle::renderRule(const QWidget *w, const QStyleOption *opt, int pseudoElement) const
1895{
1896 quint64 extraClass = 0;
1897 QStyle::State state = opt ? opt->state : QStyle::State(QStyle::State_None);
1898
1899 if (const QStyleOptionComplex *complex = qstyleoption_cast<const QStyleOptionComplex *>(opt)) {
1900 if (pseudoElement != PseudoElement_None) {
1901 // if not an active subcontrol, just pass enabled/disabled
1902 QStyle::SubControl subControl = knownPseudoElements[pseudoElement].subControl;
1903
1904 if (!(complex->activeSubControls & subControl))
1905 state = QStyle::State(state & (QStyle::State_Enabled | QStyle::State_Horizontal));
1906 }
1907
1908 switch (pseudoElement) {
1909 case PseudoElement_ComboBoxDropDown:
1910 case PseudoElement_ComboBoxArrow:
1911 state |= (complex->state & (QStyle::State_On|QStyle::State_ReadOnly));
1912 break;
1913 case PseudoElement_SpinBoxUpButton:
1914 case PseudoElement_SpinBoxDownButton:
1915 case PseudoElement_SpinBoxUpArrow:
1916 case PseudoElement_SpinBoxDownArrow:
1917#ifndef QT_NO_SPINBOX
1918 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
1919 bool on = false;
1920 bool up = pseudoElement == PseudoElement_SpinBoxUpButton
1921 || pseudoElement == PseudoElement_SpinBoxUpArrow;
1922 if ((sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) && up)
1923 on = true;
1924 else if ((sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) && !up)
1925 on = true;
1926 state |= (on ? QStyle::State_On : QStyle::State_Off);
1927 }
1928#endif // QT_NO_SPINBOX
1929 break;
1930 case PseudoElement_GroupBoxTitle:
1931 state |= (complex->state & (QStyle::State_MouseOver | QStyle::State_Sunken));
1932 break;
1933 case PseudoElement_ToolButtonMenu:
1934 case PseudoElement_ToolButtonMenuArrow:
1935 case PseudoElement_ToolButtonDownArrow:
1936 state |= complex->state & QStyle::State_MouseOver;
1937 if (complex->state & QStyle::State_Sunken ||
1938 complex->activeSubControls & QStyle::SC_ToolButtonMenu)
1939 state |= QStyle::State_Sunken;
1940 break;
1941 case PseudoElement_SliderGroove:
1942 state |= complex->state & QStyle::State_MouseOver;
1943 break;
1944 default:
1945 break;
1946 }
1947
1948 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
1949 // QStyle::State_On is set when the popup is being shown
1950 // Propagate EditField Pressed state
1951 if (pseudoElement == PseudoElement_None
1952 && (complex->activeSubControls & QStyle::SC_ComboBoxEditField)
1953 && (!(state & QStyle::State_MouseOver))) {
1954 state |= QStyle::State_Sunken;
1955 }
1956
1957 if (!combo->frame)
1958 extraClass |= PseudoClass_Frameless;
1959 if (!combo->editable)
1960 extraClass |= PseudoClass_ReadOnly;
1961 else
1962 extraClass |= PseudoClass_Editable;
1963#ifndef QT_NO_SPINBOX
1964 } else if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
1965 if (!spin->frame)
1966 extraClass |= PseudoClass_Frameless;
1967#endif // QT_NO_SPINBOX
1968 } else if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
1969 if (gb->features & QStyleOptionFrameV2::Flat)
1970 extraClass |= PseudoClass_Flat;
1971 if (gb->lineWidth == 0)
1972 extraClass |= PseudoClass_Frameless;
1973 } else if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
1974 if (tb->titleBarState & Qt::WindowMinimized) {
1975 extraClass |= PseudoClass_Minimized;
1976 }
1977 else if (tb->titleBarState & Qt::WindowMaximized)
1978 extraClass |= PseudoClass_Maximized;
1979 }
1980 } else {
1981 // handle simple style options
1982 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
1983 if (mi->menuItemType == QStyleOptionMenuItem::DefaultItem)
1984 extraClass |= PseudoClass_Default;
1985 if (mi->checkType == QStyleOptionMenuItem::Exclusive)
1986 extraClass |= PseudoClass_Exclusive;
1987 else if (mi->checkType == QStyleOptionMenuItem::NonExclusive)
1988 extraClass |= PseudoClass_NonExclusive;
1989 if (mi->checkType != QStyleOptionMenuItem::NotCheckable)
1990 extraClass |= (mi->checked) ? (PseudoClass_On|PseudoClass_Checked)
1991 : (PseudoClass_Off|PseudoClass_Unchecked);
1992 } else if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
1993 if (hdr->position == QStyleOptionHeader::OnlyOneSection)
1994 extraClass |= PseudoClass_OnlyOne;
1995 else if (hdr->position == QStyleOptionHeader::Beginning)
1996 extraClass |= PseudoClass_First;
1997 else if (hdr->position == QStyleOptionHeader::End)
1998 extraClass |= PseudoClass_Last;
1999 else if (hdr->position == QStyleOptionHeader::Middle)
2000 extraClass |= PseudoClass_Middle;
2001
2002 if (hdr->selectedPosition == QStyleOptionHeader::NextAndPreviousAreSelected)
2003 extraClass |= (PseudoClass_NextSelected | PseudoClass_PreviousSelected);
2004 else if (hdr->selectedPosition == QStyleOptionHeader::NextIsSelected)
2005 extraClass |= PseudoClass_NextSelected;
2006 else if (hdr->selectedPosition == QStyleOptionHeader::PreviousIsSelected)
2007 extraClass |= PseudoClass_PreviousSelected;
2008#ifndef QT_NO_TABWIDGET
2009 } else if (const QStyleOptionTabWidgetFrame *tab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
2010 switch (tab->shape) {
2011 case QTabBar::RoundedNorth:
2012 case QTabBar::TriangularNorth:
2013 extraClass |= PseudoClass_Top;
2014 break;
2015 case QTabBar::RoundedSouth:
2016 case QTabBar::TriangularSouth:
2017 extraClass |= PseudoClass_Bottom;
2018 break;
2019 case QTabBar::RoundedEast:
2020 case QTabBar::TriangularEast:
2021 extraClass |= PseudoClass_Left;
2022 break;
2023 case QTabBar::RoundedWest:
2024 case QTabBar::TriangularWest:
2025 extraClass |= PseudoClass_Right;
2026 break;
2027 default:
2028 break;
2029 }
2030#endif
2031#ifndef QT_NO_TABBAR
2032 } else if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
2033 if (tab->position == QStyleOptionTab::OnlyOneTab)
2034 extraClass |= PseudoClass_OnlyOne;
2035 else if (tab->position == QStyleOptionTab::Beginning)
2036 extraClass |= PseudoClass_First;
2037 else if (tab->position == QStyleOptionTab::End)
2038 extraClass |= PseudoClass_Last;
2039 else if (tab->position == QStyleOptionTab::Middle)
2040 extraClass |= PseudoClass_Middle;
2041
2042 if (tab->selectedPosition == QStyleOptionTab::NextIsSelected)
2043 extraClass |= PseudoClass_NextSelected;
2044 else if (tab->selectedPosition == QStyleOptionTab::PreviousIsSelected)
2045 extraClass |= PseudoClass_PreviousSelected;
2046
2047 switch (tab->shape) {
2048 case QTabBar::RoundedNorth:
2049 case QTabBar::TriangularNorth:
2050 extraClass |= PseudoClass_Top;
2051 break;
2052 case QTabBar::RoundedSouth:
2053 case QTabBar::TriangularSouth:
2054 extraClass |= PseudoClass_Bottom;
2055 break;
2056 case QTabBar::RoundedEast:
2057 case QTabBar::TriangularEast:
2058 extraClass |= PseudoClass_Left;
2059 break;
2060 case QTabBar::RoundedWest:
2061 case QTabBar::TriangularWest:
2062 extraClass |= PseudoClass_Right;
2063 break;
2064 default:
2065 break;
2066 }
2067#endif // QT_NO_TABBAR
2068 } else if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
2069 if (btn->features & QStyleOptionButton::Flat)
2070 extraClass |= PseudoClass_Flat;
2071 if (btn->features & QStyleOptionButton::DefaultButton)
2072 extraClass |= PseudoClass_Default;
2073 } else if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2074 if (frm->lineWidth == 0)
2075 extraClass |= PseudoClass_Frameless;
2076 if (const QStyleOptionFrameV2 *frame2 = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt)) {
2077 if (frame2->features & QStyleOptionFrameV2::Flat)
2078 extraClass |= PseudoClass_Flat;
2079 }
2080 }
2081#ifndef QT_NO_TOOLBAR
2082 else if (const QStyleOptionToolBar *tb = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
2083 if (tb->toolBarArea == Qt::LeftToolBarArea)
2084 extraClass |= PseudoClass_Left;
2085 else if (tb->toolBarArea == Qt::RightToolBarArea)
2086 extraClass |= PseudoClass_Right;
2087 else if (tb->toolBarArea == Qt::TopToolBarArea)
2088 extraClass |= PseudoClass_Top;
2089 else if (tb->toolBarArea == Qt::BottomToolBarArea)
2090 extraClass |= PseudoClass_Bottom;
2091
2092 if (tb->positionWithinLine == QStyleOptionToolBar::Beginning)
2093 extraClass |= PseudoClass_First;
2094 else if (tb->positionWithinLine == QStyleOptionToolBar::Middle)
2095 extraClass |= PseudoClass_Middle;
2096 else if (tb->positionWithinLine == QStyleOptionToolBar::End)
2097 extraClass |= PseudoClass_Last;
2098 else if (tb->positionWithinLine == QStyleOptionToolBar::OnlyOne)
2099 extraClass |= PseudoClass_OnlyOne;
2100 }
2101#endif // QT_NO_TOOLBAR
2102#ifndef QT_NO_TOOLBOX
2103 else if (const QStyleOptionToolBoxV2 *tab = qstyleoption_cast<const QStyleOptionToolBoxV2 *>(opt)) {
2104 if (tab->position == QStyleOptionToolBoxV2::OnlyOneTab)
2105 extraClass |= PseudoClass_OnlyOne;
2106 else if (tab->position == QStyleOptionToolBoxV2::Beginning)
2107 extraClass |= PseudoClass_First;
2108 else if (tab->position == QStyleOptionToolBoxV2::End)
2109 extraClass |= PseudoClass_Last;
2110 else if (tab->position == QStyleOptionToolBoxV2::Middle)
2111 extraClass |= PseudoClass_Middle;
2112
2113 if (tab->selectedPosition == QStyleOptionToolBoxV2::NextIsSelected)
2114 extraClass |= PseudoClass_NextSelected;
2115 else if (tab->selectedPosition == QStyleOptionToolBoxV2::PreviousIsSelected)
2116 extraClass |= PseudoClass_PreviousSelected;
2117 }
2118#endif // QT_NO_TOOLBOX
2119#ifndef QT_NO_DOCKWIDGET
2120 else if (const QStyleOptionDockWidgetV2 *dw = qstyleoption_cast<const QStyleOptionDockWidgetV2 *>(opt)) {
2121 if (dw->verticalTitleBar)
2122 extraClass |= PseudoClass_Vertical;
2123 else
2124 extraClass |= PseudoClass_Horizontal;
2125 if (dw->closable)
2126 extraClass |= PseudoClass_Closable;
2127 if (dw->floatable)
2128 extraClass |= PseudoClass_Floatable;
2129 if (dw->movable)
2130 extraClass |= PseudoClass_Movable;
2131 }
2132#endif // QT_NO_DOCKWIDGET
2133#ifndef QT_NO_ITEMVIEWS
2134 else if (const QStyleOptionViewItemV2 *v2 = qstyleoption_cast<const QStyleOptionViewItemV2 *>(opt)) {
2135 if (v2->features & QStyleOptionViewItemV2::Alternate)
2136 extraClass |= PseudoClass_Alternate;
2137 if (const QStyleOptionViewItemV4 *v4 = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) {
2138 if (v4->viewItemPosition == QStyleOptionViewItemV4::OnlyOne)
2139 extraClass |= PseudoClass_OnlyOne;
2140 else if (v4->viewItemPosition == QStyleOptionViewItemV4::Beginning)
2141 extraClass |= PseudoClass_First;
2142 else if (v4->viewItemPosition == QStyleOptionViewItemV4::End)
2143 extraClass |= PseudoClass_Last;
2144 else if (v4->viewItemPosition == QStyleOptionViewItemV4::Middle)
2145 extraClass |= PseudoClass_Middle;
2146 }
2147 }
2148#endif
2149#ifndef QT_NO_LINEEDIT
2150 // LineEdit sets Sunken flag to indicate Sunken frame (argh)
2151 if (const QLineEdit *lineEdit = qobject_cast<const QLineEdit *>(w)) {
2152 state &= ~QStyle::State_Sunken;
2153 if (lineEdit->hasFrame()) {
2154 extraClass &= ~PseudoClass_Frameless;
2155 } else {
2156 extraClass |= PseudoClass_Frameless;
2157 }
2158 } else
2159#endif
2160 { } // required for the above ifdef'ery
2161 }
2162
2163 return renderRule(w, pseudoElement, pseudoClass(state) | extraClass);
2164}
2165
2166bool QStyleSheetStyle::hasStyleRule(const QWidget *w, int part) const
2167{
2168 QHash<int, bool> &cache = (*hasStyleRuleCache)[w];
2169 QHash<int, bool>::const_iterator cacheIt = cache.constFind(part);
2170 if (cacheIt != cache.constEnd())
2171 return cacheIt.value();
2172
2173 if (!initWidget(w))
2174 return false;
2175
2176
2177 const QVector<StyleRule> &rules = styleRules(w);
2178 if (part == PseudoElement_None) {
2179 bool result = w && !rules.isEmpty();
2180 cache[part] = result;
2181 return result;
2182 }
2183
2184 QString pseudoElement = QLatin1String(knownPseudoElements[part].name);
2185 QVector<Declaration> declarations;
2186 for (int i = 0; i < rules.count(); i++) {
2187 const Selector& selector = rules.at(i).selectors.at(0);
2188 if (pseudoElement.compare(selector.pseudoElement(), Qt::CaseInsensitive) == 0) {
2189 cache[part] = true;
2190 return true;
2191 }
2192 }
2193
2194 cache[part] = false;
2195 return false;
2196}
2197
2198static Origin defaultOrigin(int pe)
2199{
2200 switch (pe) {
2201 case PseudoElement_ScrollBarAddPage:
2202 case PseudoElement_ScrollBarSubPage:
2203 case PseudoElement_ScrollBarAddLine:
2204 case PseudoElement_ScrollBarSubLine:
2205 case PseudoElement_ScrollBarFirst:
2206 case PseudoElement_ScrollBarLast:
2207 case PseudoElement_GroupBoxTitle:
2208 case PseudoElement_GroupBoxIndicator: // never used
2209 case PseudoElement_ToolButtonMenu:
2210 case PseudoElement_SliderAddPage:
2211 case PseudoElement_SliderSubPage:
2212 return Origin_Border;
2213
2214 case PseudoElement_SpinBoxUpButton:
2215 case PseudoElement_SpinBoxDownButton:
2216 case PseudoElement_PushButtonMenuIndicator:
2217 case PseudoElement_ComboBoxDropDown:
2218 case PseudoElement_ToolButtonDownArrow:
2219 case PseudoElement_MenuCheckMark:
2220 case PseudoElement_MenuIcon:
2221 case PseudoElement_MenuRightArrow:
2222 return Origin_Padding;
2223
2224 case PseudoElement_Indicator:
2225 case PseudoElement_ExclusiveIndicator:
2226 case PseudoElement_ComboBoxArrow:
2227 case PseudoElement_ScrollBarSlider:
2228 case PseudoElement_ScrollBarUpArrow:
2229 case PseudoElement_ScrollBarDownArrow:
2230 case PseudoElement_ScrollBarLeftArrow:
2231 case PseudoElement_ScrollBarRightArrow:
2232 case PseudoElement_SpinBoxUpArrow:
2233 case PseudoElement_SpinBoxDownArrow:
2234 case PseudoElement_ToolButtonMenuArrow:
2235 case PseudoElement_HeaderViewUpArrow:
2236 case PseudoElement_HeaderViewDownArrow:
2237 case PseudoElement_SliderGroove:
2238 case PseudoElement_SliderHandle:
2239 return Origin_Content;
2240
2241 default:
2242 return Origin_Margin;
2243 }
2244}
2245
2246static Qt::Alignment defaultPosition(int pe)
2247{
2248 switch (pe) {
2249 case PseudoElement_Indicator:
2250 case PseudoElement_ExclusiveIndicator:
2251 case PseudoElement_MenuCheckMark:
2252 case PseudoElement_MenuIcon:
2253 return Qt::AlignLeft | Qt::AlignVCenter;
2254
2255 case PseudoElement_ScrollBarAddLine:
2256 case PseudoElement_ScrollBarLast:
2257 case PseudoElement_SpinBoxDownButton:
2258 case PseudoElement_PushButtonMenuIndicator:
2259 case PseudoElement_ToolButtonDownArrow:
2260 return Qt::AlignRight | Qt::AlignBottom;
2261
2262 case PseudoElement_ScrollBarSubLine:
2263 case PseudoElement_ScrollBarFirst:
2264 case PseudoElement_SpinBoxUpButton:
2265 case PseudoElement_ComboBoxDropDown:
2266 case PseudoElement_ToolButtonMenu:
2267 case PseudoElement_DockWidgetCloseButton:
2268 case PseudoElement_DockWidgetFloatButton:
2269 return Qt::AlignRight | Qt::AlignTop;
2270
2271 case PseudoElement_ScrollBarUpArrow:
2272 case PseudoElement_ScrollBarDownArrow:
2273 case PseudoElement_ScrollBarLeftArrow:
2274 case PseudoElement_ScrollBarRightArrow:
2275 case PseudoElement_SpinBoxUpArrow:
2276 case PseudoElement_SpinBoxDownArrow:
2277 case PseudoElement_ComboBoxArrow:
2278 case PseudoElement_DownArrow:
2279 case PseudoElement_ToolButtonMenuArrow:
2280 case PseudoElement_SliderGroove:
2281 return Qt::AlignCenter;
2282
2283 case PseudoElement_GroupBoxTitle:
2284 case PseudoElement_GroupBoxIndicator: // never used
2285 return Qt::AlignLeft | Qt::AlignTop;
2286
2287 case PseudoElement_HeaderViewUpArrow:
2288 case PseudoElement_HeaderViewDownArrow:
2289 case PseudoElement_MenuRightArrow:
2290 return Qt::AlignRight | Qt::AlignVCenter;
2291
2292 default:
2293 return 0;
2294 }
2295}
2296
2297QSize QStyleSheetStyle::defaultSize(const QWidget *w, QSize sz, const QRect& rect, int pe) const
2298{
2299 QStyle *base = baseStyle();
2300
2301 switch (pe) {
2302 case PseudoElement_Indicator:
2303 case PseudoElement_MenuCheckMark:
2304 if (sz.width() == -1)
2305 sz.setWidth(base->pixelMetric(PM_IndicatorWidth, 0, w));
2306 if (sz.height() == -1)
2307 sz.setHeight(base->pixelMetric(PM_IndicatorHeight, 0, w));
2308 break;
2309
2310 case PseudoElement_ExclusiveIndicator:
2311 case PseudoElement_GroupBoxIndicator:
2312 if (sz.width() == -1)
2313 sz.setWidth(base->pixelMetric(PM_ExclusiveIndicatorWidth, 0, w));
2314 if (sz.height() == -1)
2315 sz.setHeight(base->pixelMetric(PM_ExclusiveIndicatorHeight, 0, w));
2316 break;
2317
2318 case PseudoElement_PushButtonMenuIndicator: {
2319 int pm = base->pixelMetric(PM_MenuButtonIndicator, 0, w);
2320 if (sz.width() == -1)
2321 sz.setWidth(pm);
2322 if (sz.height() == -1)
2323 sz.setHeight(pm);
2324 }
2325 break;
2326
2327 case PseudoElement_ComboBoxDropDown:
2328 if (sz.width() == -1)
2329 sz.setWidth(16);
2330 break;
2331
2332 case PseudoElement_ComboBoxArrow:
2333 case PseudoElement_DownArrow:
2334 case PseudoElement_ToolButtonMenuArrow:
2335 case PseudoElement_ToolButtonDownArrow:
2336 case PseudoElement_MenuRightArrow:
2337 if (sz.width() == -1)
2338 sz.setWidth(13);
2339 if (sz.height() == -1)
2340 sz.setHeight(13);
2341 break;
2342
2343 case PseudoElement_SpinBoxUpButton:
2344 case PseudoElement_SpinBoxDownButton:
2345 if (sz.width() == -1)
2346 sz.setWidth(16);
2347 if (sz.height() == -1)
2348 sz.setHeight(rect.height()/2);
2349 break;
2350
2351 case PseudoElement_ToolButtonMenu:
2352 if (sz.width() == -1)
2353 sz.setWidth(base->pixelMetric(PM_MenuButtonIndicator, 0, w));
2354 break;
2355
2356 case PseudoElement_HeaderViewUpArrow:
2357 case PseudoElement_HeaderViewDownArrow: {
2358 int pm = base->pixelMetric(PM_HeaderMargin, 0, w);
2359 if (sz.width() == -1)
2360 sz.setWidth(pm);
2361 if (sz.height() == 1)
2362 sz.setHeight(pm);
2363 break;
2364 }
2365
2366 case PseudoElement_ScrollBarFirst:
2367 case PseudoElement_ScrollBarLast:
2368 case PseudoElement_ScrollBarAddLine:
2369 case PseudoElement_ScrollBarSubLine:
2370 case PseudoElement_ScrollBarSlider: {
2371 int pm = pixelMetric(QStyle::PM_ScrollBarExtent, 0, w);
2372 if (sz.width() == -1)
2373 sz.setWidth(pm);
2374 if (sz.height() == -1)
2375 sz.setHeight(pm);
2376 break;
2377 }
2378
2379 case PseudoElement_DockWidgetCloseButton:
2380 case PseudoElement_DockWidgetFloatButton: {
2381 int iconSize = pixelMetric(PM_SmallIconSize, 0, w);
2382 return QSize(iconSize, iconSize);
2383 }
2384
2385 default:
2386 break;
2387 }
2388
2389 // expand to rectangle
2390 if (sz.height() == -1)
2391 sz.setHeight(rect.height());
2392 if (sz.width() == -1)
2393 sz.setWidth(rect.width());
2394
2395 return sz;
2396}
2397
2398static PositionMode defaultPositionMode(int pe)
2399{
2400 switch (pe) {
2401 case PseudoElement_ScrollBarFirst:
2402 case PseudoElement_ScrollBarLast:
2403 case PseudoElement_ScrollBarAddLine:
2404 case PseudoElement_ScrollBarSubLine:
2405 case PseudoElement_ScrollBarAddPage:
2406 case PseudoElement_ScrollBarSubPage:
2407 case PseudoElement_ScrollBarSlider:
2408 case PseudoElement_SliderGroove:
2409 case PseudoElement_SliderHandle:
2410 case PseudoElement_TabWidgetPane:
2411 return PositionMode_Absolute;
2412 default:
2413 return PositionMode_Static;
2414 }
2415}
2416
2417QRect QStyleSheetStyle::positionRect(const QWidget *w, const QRenderRule &rule2, int pe,
2418 const QRect &originRect, Qt::LayoutDirection dir) const
2419{
2420 const QStyleSheetPositionData *p = rule2.position();
2421 PositionMode mode = (p && p->mode != PositionMode_Unknown) ? p->mode : defaultPositionMode(pe);
2422 Qt::Alignment position = (p && p->position != 0) ? p->position : defaultPosition(pe);
2423 QRect r;
2424
2425 if (mode != PositionMode_Absolute) {
2426 QSize sz = defaultSize(w, rule2.size(), originRect, pe);
2427 sz = sz.expandedTo(rule2.minimumContentsSize());
2428 r = QStyle::alignedRect(dir, position, sz, originRect);
2429 if (p) {
2430 int left = p->left ? p->left : -p->right;
2431 int top = p->top ? p->top : -p->bottom;
2432 r.translate(dir == Qt::LeftToRight ? left : -left, top);
2433 }
2434 } else {
2435 r = p ? originRect.adjusted(dir == Qt::LeftToRight ? p->left : p->right, p->top,
2436 dir == Qt::LeftToRight ? -p->right : -p->left, -p->bottom)
2437 : originRect;
2438 if (rule2.hasContentsSize()) {
2439 QSize sz = rule2.size().expandedTo(rule2.minimumContentsSize());
2440 if (sz.width() == -1) sz.setWidth(r.width());
2441 if (sz.height() == -1) sz.setHeight(r.height());
2442 r = QStyle::alignedRect(dir, position, sz, r);
2443 }
2444 }
2445 return r;
2446}
2447
2448QRect QStyleSheetStyle::positionRect(const QWidget *w, const QRenderRule& rule1, const QRenderRule& rule2, int pe,
2449 const QRect& rect, Qt::LayoutDirection dir) const
2450{
2451 const QStyleSheetPositionData *p = rule2.position();
2452 Origin origin = (p && p->origin != Origin_Unknown) ? p->origin : defaultOrigin(pe);
2453 QRect originRect = rule1.originRect(rect, origin);
2454 return positionRect(w, rule2, pe, originRect, dir);
2455}
2456
2457
2458/** \internal
2459 For widget that have an embedded widget (such as combobox) return that embedded widget.
2460 otherwise return the widget itself
2461 */
2462static QWidget *embeddedWidget(QWidget *w)
2463{
2464#ifndef QT_NO_COMBOBOX
2465 if (QComboBox *cmb = qobject_cast<QComboBox *>(w)) {
2466 if (cmb->isEditable())
2467 return cmb->lineEdit();
2468 else
2469 return cmb;
2470 }
2471#endif
2472
2473#ifndef QT_NO_SPINBOX
2474 if (QAbstractSpinBox *sb = qobject_cast<QAbstractSpinBox *>(w))
2475 return qFindChild<QLineEdit *>(sb);
2476#endif
2477
2478#ifndef QT_NO_SCROLLAREA
2479 if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(w))
2480 return sa->viewport();
2481#endif
2482
2483 return w;
2484}
2485
2486/** \internal
2487 in case w is an embedded widget, return the container widget
2488 (i.e, the widget for which the rules actualy apply)
2489 (exemple, if w is a lineedit embedded in a combobox, return the combobox)
2490
2491 if w is not embedded, return w itself
2492*/
2493static QWidget *containerWidget(const QWidget *w)
2494{
2495#ifndef QT_NO_LINEEDIT
2496 if (qobject_cast<const QLineEdit *>(w)) {
2497 //if the QLineEdit is an embeddedWidget, we need the rule of the real widget
2498#ifndef QT_NO_COMBOBOX
2499 if (qobject_cast<const QComboBox *>(w->parentWidget()))
2500 return w->parentWidget();
2501#endif
2502#ifndef QT_NO_SPINBOX
2503 if (qobject_cast<const QAbstractSpinBox *>(w->parentWidget()))
2504 return w->parentWidget();
2505#endif
2506 }
2507#endif // QT_NO_LINEEDIT
2508
2509#ifndef QT_NO_SCROLLAREA
2510 if (const QAbstractScrollArea *sa = qobject_cast<const QAbstractScrollArea *>(w->parentWidget())) {
2511 if (sa->viewport() == w)
2512 return w->parentWidget();
2513 }
2514#endif
2515
2516 return const_cast<QWidget *>(w);
2517}
2518
2519/** \internal
2520 returns true if the widget can NOT be styled directly
2521 */
2522static bool unstylable(const QWidget *w)
2523{
2524 if (w->windowType() == Qt::Desktop)
2525 return true;
2526
2527 if (!w->styleSheet().isEmpty())
2528 return false;
2529
2530 if (containerWidget(w) != w)
2531 return true;
2532
2533#ifndef QT_NO_FRAME
2534 // detect QComboBoxPrivateContainer
2535 else if (qobject_cast<const QFrame *>(w)) {
2536 if (0
2537#ifndef QT_NO_COMBOBOX
2538 || qobject_cast<const QComboBox *>(w->parentWidget())
2539#endif
2540 )
2541 return true;
2542 }
2543#endif
2544 return false;
2545}
2546
2547static quint64 extendedPseudoClass(const QWidget *w)
2548{
2549 quint64 pc = w->isWindow() ? quint64(PseudoClass_Window) : 0;
2550 if (const QAbstractSlider *slider = qobject_cast<const QAbstractSlider *>(w)) {
2551 pc |= ((slider->orientation() == Qt::Vertical) ? PseudoClass_Vertical : PseudoClass_Horizontal);
2552 } else
2553#ifndef QT_NO_COMBOBOX
2554 if (const QComboBox *combo = qobject_cast<const QComboBox *>(w)) {
2555 if (combo->isEditable())
2556 pc |= (combo->isEditable() ? PseudoClass_Editable : PseudoClass_ReadOnly);
2557 } else
2558#endif
2559#ifndef QT_NO_LINEEDIT
2560 if (const QLineEdit *edit = qobject_cast<const QLineEdit *>(w)) {
2561 pc |= (edit->isReadOnly() ? PseudoClass_ReadOnly : PseudoClass_Editable);
2562 } else
2563#endif
2564 { } // required for the above ifdef'ery to work
2565 return pc;
2566}
2567
2568// sets up the geometry of the widget. We set a dynamic property when
2569// we modify the min/max size of the widget. The min/max size is restored
2570// to their original value when a new stylesheet that does not contain
2571// the CSS properties is set and when the widget has this dynamic property set.
2572// This way we don't trample on users who had setup a min/max size in code and
2573// don't use stylesheets at all.
2574void QStyleSheetStyle::setGeometry(QWidget *w)
2575{
2576 QRenderRule rule = renderRule(w, PseudoElement_None, PseudoClass_Enabled | extendedPseudoClass(w));
2577 const QStyleSheetGeometryData *geo = rule.geometry();
2578 if (w->property("_q_stylesheet_minw").toBool()
2579 && ((!rule.hasGeometry() || geo->minWidth == -1))) {
2580 w->setMinimumWidth(0);
2581 w->setProperty("_q_stylesheet_minw", QVariant());
2582 }
2583 if (w->property("_q_stylesheet_minh").toBool()
2584 && ((!rule.hasGeometry() || geo->minHeight == -1))) {
2585 w->setMinimumHeight(0);
2586 w->setProperty("_q_stylesheet_minh", QVariant());
2587 }
2588 if (w->property("_q_stylesheet_maxw").toBool()
2589 && ((!rule.hasGeometry() || geo->maxWidth == -1))) {
2590 w->setMaximumWidth(QWIDGETSIZE_MAX);
2591 w->setProperty("_q_stylesheet_maxw", QVariant());
2592 }
2593 if (w->property("_q_stylesheet_maxh").toBool()
2594 && ((!rule.hasGeometry() || geo->maxHeight == -1))) {
2595 w->setMaximumHeight(QWIDGETSIZE_MAX);
2596 w->setProperty("_q_stylesheet_maxh", QVariant());
2597 }
2598
2599
2600 if (rule.hasGeometry()) {
2601 if (geo->minWidth != -1) {
2602 w->setProperty("_q_stylesheet_minw", true);
2603 w->setMinimumWidth(rule.boxSize(QSize(qMax(geo->width, geo->minWidth), 0)).width());
2604 }
2605 if (geo->minHeight != -1) {
2606 w->setProperty("_q_stylesheet_minh", true);
2607 w->setMinimumHeight(rule.boxSize(QSize(0, qMax(geo->height, geo->minHeight))).height());
2608 }
2609 if (geo->maxWidth != -1) {
2610 w->setProperty("_q_stylesheet_maxw", true);
2611 w->setMaximumWidth(rule.boxSize(QSize(qMin(geo->width == -1 ? QWIDGETSIZE_MAX : geo->width,
2612 geo->maxWidth == -1 ? QWIDGETSIZE_MAX : geo->maxWidth), 0)).width());
2613 }
2614 if (geo->maxHeight != -1) {
2615 w->setProperty("_q_stylesheet_maxh", true);
2616 w->setMaximumHeight(rule.boxSize(QSize(0, qMin(geo->height == -1 ? QWIDGETSIZE_MAX : geo->height,
2617 geo->maxHeight == -1 ? QWIDGETSIZE_MAX : geo->maxHeight))).height());
2618 }
2619 }
2620}
2621
2622void QStyleSheetStyle::setProperties(QWidget *w)
2623{
2624 QHash<QString, QVariant> propertyHash;
2625 QVector<Declaration> decls = declarations(styleRules(w), QString());
2626
2627 // run through the declarations in order
2628 for (int i = 0; i < decls.count(); i++) {
2629 const Declaration &decl = decls.at(i);
2630 QString property = decl.d->property;
2631 if (!property.startsWith(QLatin1String("qproperty-"), Qt::CaseInsensitive))
2632 continue;
2633 property.remove(0, 10); // strip "qproperty-"
2634 const QVariant value = w->property(property.toLatin1());
2635 const QMetaObject *metaObject = w->metaObject();
2636 int index = metaObject->indexOfProperty(property.toLatin1());
2637 if (index == -1) {
2638 qWarning() << w << " does not have a property named " << property;
2639 continue;
2640 }
2641 QMetaProperty metaProperty = metaObject->property(index);
2642 if (!metaProperty.isWritable() || !metaProperty.isDesignable()) {
2643 qWarning() << w << " cannot design property named " << property;
2644 continue;
2645 }
2646 QVariant v;
2647 switch (value.type()) {
2648 case QVariant::Icon: v = decl.iconValue(); break;
2649 case QVariant::Image: v = QImage(decl.uriValue()); break;
2650 case QVariant::Pixmap: v = QPixmap(decl.uriValue()); break;
2651 case QVariant::Rect: v = decl.rectValue(); break;
2652 case QVariant::Size: v = decl.sizeValue(); break;
2653 case QVariant::Color: v = decl.colorValue(); break;
2654 case QVariant::Brush: v = decl.brushValue(); break;
2655#ifndef QT_NO_SHORTCUT
2656 case QVariant::KeySequence: v = QKeySequence(decl.d->values.at(0).variant.toString()); break;
2657#endif
2658 default: v = decl.d->values.at(0).variant; break;
2659 }
2660 propertyHash[property] = v;
2661 }
2662 // apply the values
2663 const QList<QString> properties = propertyHash.keys();
2664 for (int i = 0; i < properties.count(); i++) {
2665 const QString &property = properties.at(i);
2666 w->setProperty(property.toLatin1(), propertyHash[property]);
2667 }
2668}
2669
2670void QStyleSheetStyle::setPalette(QWidget *w)
2671{
2672 struct RuleRoleMap {
2673 int state;
2674 QPalette::ColorGroup group;
2675 } map[3] = {
2676 { PseudoClass_Active | PseudoClass_Enabled, QPalette::Active },
2677 { PseudoClass_Disabled, QPalette::Disabled },
2678 { PseudoClass_Enabled, QPalette::Inactive }
2679 };
2680
2681 QPalette p = w->palette();
2682 QWidget *ew = embeddedWidget(w);
2683
2684 for (int i = 0; i < 3; i++) {
2685 QRenderRule rule = renderRule(w, PseudoElement_None, map[i].state | extendedPseudoClass(w));
2686 if (i == 0) {
2687 if (!w->property("_q_styleSheetWidgetFont").isValid()) {
2688 saveWidgetFont(w, w->font());
2689 }
2690 updateStyleSheetFont(w);
2691 if (ew != w)
2692 updateStyleSheetFont(ew);
2693 }
2694
2695 rule.configurePalette(&p, map[i].group, ew, ew != w);
2696 }
2697
2698 customPaletteWidgets->insert(w, w->palette());
2699 w->setPalette(p);
2700 if (ew != w)
2701 ew->setPalette(p);
2702}
2703
2704void QStyleSheetStyle::unsetPalette(QWidget *w)
2705{
2706 if (customPaletteWidgets->contains(w)) {
2707 QPalette p = customPaletteWidgets->value(w);
2708 w->setPalette(p);
2709 QWidget *ew = embeddedWidget(w);
2710 if (ew != w)
2711 ew->setPalette(p);
2712 customPaletteWidgets->remove(w);
2713 }
2714 QVariant oldFont = w->property("_q_styleSheetWidgetFont");
2715 if (oldFont.isValid()) {
2716 w->setFont(qVariantValue<QFont>(oldFont));
2717 }
2718 if (autoFillDisabledWidgets->contains(w)) {
2719 embeddedWidget(w)->setAutoFillBackground(true);
2720 autoFillDisabledWidgets->remove(w);
2721 }
2722}
2723
2724static void updateWidgets(const QList<const QWidget *>& widgets)
2725{
2726 if (!styleRulesCache->isEmpty() || !hasStyleRuleCache->isEmpty() || !renderRulesCache->isEmpty()) {
2727 for (int i = 0; i < widgets.size(); ++i) {
2728 const QWidget *widget = widgets.at(i);
2729 styleRulesCache->remove(widget);
2730 hasStyleRuleCache->remove(widget);
2731 renderRulesCache->remove(widget);
2732 }
2733 }
2734 for (int i = 0; i < widgets.size(); ++i) {
2735 QWidget *widget = const_cast<QWidget *>(widgets.at(i));
2736 if (widget == 0)
2737 continue;
2738 widget->style()->polish(widget);
2739 QEvent event(QEvent::StyleChange);
2740 qApp->sendEvent(widget, &event);
2741 widget->update();
2742 widget->updateGeometry();
2743 }
2744}
2745
2746/////////////////////////////////////////////////////////////////////////////////////////
2747// The stylesheet style
2748int QStyleSheetStyle::numinstances = 0;
2749
2750QStyleSheetStyle::QStyleSheetStyle(QStyle *base)
2751 : QWindowsStyle(*new QStyleSheetStylePrivate), base(base), refcount(1)
2752{
2753 ++numinstances;
2754 if (numinstances == 1) {
2755 styleRulesCache = new QHash<const QWidget *, QVector<StyleRule> >;
2756 hasStyleRuleCache = new QHash<const QWidget *, QHash<int, bool> >;
2757 renderRulesCache = new QHash<const QWidget *, QRenderRules>;
2758 customPaletteWidgets = new QHash<const QWidget *, QPalette>;
2759 styleSheetCache = new QHash<const void *, StyleSheet>;
2760 autoFillDisabledWidgets = new QSet<const QWidget *>;
2761 }
2762}
2763
2764QStyleSheetStyle::~QStyleSheetStyle()
2765{
2766 --numinstances;
2767 if (numinstances == 0) {
2768 delete styleRulesCache;
2769 styleRulesCache = 0;
2770 delete hasStyleRuleCache;
2771 hasStyleRuleCache = 0;
2772 delete renderRulesCache;
2773 renderRulesCache = 0;
2774 delete customPaletteWidgets;
2775 customPaletteWidgets = 0;
2776 delete styleSheetCache;
2777 styleSheetCache = 0;
2778 delete autoFillDisabledWidgets;
2779 autoFillDisabledWidgets = 0;
2780 }
2781}
2782QStyle *QStyleSheetStyle::baseStyle() const
2783{
2784 if (base)
2785 return base;
2786 if (QStyleSheetStyle *me = qobject_cast<QStyleSheetStyle *>(qApp->style()))
2787 return me->base;
2788 return qApp->style();
2789}
2790
2791void QStyleSheetStyle::widgetDestroyed(QObject *o)
2792{
2793 styleRulesCache->remove((const QWidget *)o);
2794 hasStyleRuleCache->remove((const QWidget *)o);
2795 renderRulesCache->remove((const QWidget *)o);
2796 customPaletteWidgets->remove((const QWidget *)o);
2797 styleSheetCache->remove((const QWidget *)o);
2798 autoFillDisabledWidgets->remove((const QWidget *)o);
2799}
2800
2801/*!
2802 * Make sure that the cache will be clean by connecting destroyed if needed.
2803 * return false if the widget is not stylable;
2804 */
2805bool QStyleSheetStyle::initWidget(const QWidget *w) const
2806{
2807 if (!w)
2808 return false;
2809 if(w->testAttribute(Qt::WA_StyleSheet))
2810 return true;
2811
2812 if(unstylable(w))
2813 return false;
2814
2815 const_cast<QWidget *>(w)->setAttribute(Qt::WA_StyleSheet, true);
2816 QObject::connect(w, SIGNAL(destroyed(QObject*)), this, SLOT(widgetDestroyed(QObject*)));
2817 return true;
2818}
2819
2820void QStyleSheetStyle::polish(QWidget *w)
2821{
2822 baseStyle()->polish(w);
2823 RECURSION_GUARD(return)
2824
2825 if (!initWidget(w))
2826 return;
2827
2828 if (styleRulesCache->contains(w)) {
2829 // the widget accessed its style pointer before polish (or repolish)
2830 // (exemple: the QAbstractSpinBox constructor ask for the stylehint)
2831 styleRulesCache->remove(w);
2832 hasStyleRuleCache->remove(w);
2833 renderRulesCache->remove(w);
2834 }
2835 setGeometry(w);
2836 setProperties(w);
2837 unsetPalette(w);
2838 setPalette(w);
2839
2840 //set the WA_Hover attribute if one of the selector depends of the hover state
2841 QVector<StyleRule> rules = styleRules(w);
2842 for (int i = 0; i < rules.count(); i++) {
2843 const Selector& selector = rules.at(i).selectors.at(0);
2844 quint64 negated = 0;
2845 quint64 cssClass = selector.pseudoClass(&negated);
2846 if ( cssClass & PseudoClass_Hover || negated & PseudoClass_Hover) {
2847 w->setAttribute(Qt::WA_Hover);
2848 embeddedWidget(w)->setAttribute(Qt::WA_Hover);
2849 }
2850 }
2851
2852
2853#ifndef QT_NO_SCROLLAREA
2854 if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(w)) {
2855 QRenderRule rule = renderRule(sa, PseudoElement_None, PseudoClass_Enabled);
2856 if ((rule.hasBorder() && rule.border()->hasBorderImage())
2857 || (rule.hasBackground() && !rule.background()->pixmap.isNull())) {
2858 QObject::disconnect(sa->horizontalScrollBar(), SIGNAL(valueChanged(int)),
2859 sa, SLOT(update()));
2860 QObject::disconnect(sa->verticalScrollBar(), SIGNAL(valueChanged(int)),
2861 sa, SLOT(update()));
2862 QObject::connect(sa->horizontalScrollBar(), SIGNAL(valueChanged(int)),
2863 sa, SLOT(update()));
2864 QObject::connect(sa->verticalScrollBar(), SIGNAL(valueChanged(int)),
2865 sa, SLOT(update()));
2866 }
2867 }
2868#endif
2869
2870#ifndef QT_NO_PROGRESSBAR
2871 if (QProgressBar *pb = qobject_cast<QProgressBar *>(w)) {
2872 QWindowsStyle::polish(pb);
2873 }
2874#endif
2875
2876 QRenderRule rule = renderRule(w, PseudoElement_None, PseudoClass_Any);
2877 if (rule.hasDrawable() || rule.hasBox()) {
2878 if (w->metaObject() == &QWidget::staticMetaObject
2879#ifndef QT_NO_MENUBAR
2880 || qobject_cast<QMenuBar *>(w)
2881#endif
2882#ifndef QT_NO_MENU
2883 || qobject_cast<QMenu *>(w)
2884#endif
2885#ifndef QT_NO_ITEMVIEWS
2886 || qobject_cast<QHeaderView *>(w)
2887#endif
2888#ifndef QT_NO_TABBAR
2889 || qobject_cast<QTabBar *>(w)
2890#endif
2891#ifndef QT_NO_FRAME
2892 || qobject_cast<QFrame *>(w)
2893#endif
2894#ifndef QT_NO_MAINWINDOW
2895 || qobject_cast<QMainWindow *>(w)
2896#endif
2897#ifndef QT_NO_MDIAREA
2898 || qobject_cast<QMdiSubWindow *>(w)
2899#endif
2900 || qobject_cast<QDialog *>(w)) {
2901 w->setAttribute(Qt::WA_StyledBackground, true);
2902 }
2903 QWidget *ew = embeddedWidget(w);
2904 if (ew->autoFillBackground()) {
2905 ew->setAutoFillBackground(false);
2906 autoFillDisabledWidgets->insert(w);
2907 if (ew != w) { //eg. viewport of a scrollarea
2908 //(in order to draw the background anyway in case we don't.)
2909 ew->setAttribute(Qt::WA_StyledBackground, true);
2910 }
2911 }
2912 if (!rule.hasBackground() || rule.background()->isTransparent() || rule.hasBox()
2913 || (!rule.hasNativeBorder() && !rule.border()->isOpaque()))
2914 w->setAttribute(Qt::WA_OpaquePaintEvent, false);
2915 }
2916}
2917
2918void QStyleSheetStyle::polish(QApplication *app)
2919{
2920 baseStyle()->polish(app);
2921}
2922
2923void QStyleSheetStyle::polish(QPalette &pal)
2924{
2925 baseStyle()->polish(pal);
2926}
2927
2928void QStyleSheetStyle::repolish(QWidget *w)
2929{
2930 QList<const QWidget *> children = qFindChildren<const QWidget *>(w, QString());
2931 children.append(w);
2932 styleSheetCache->remove(w);
2933 updateWidgets(children);
2934}
2935
2936void QStyleSheetStyle::repolish(QApplication *app)
2937{
2938 Q_UNUSED(app);
2939 const QList<const QWidget*> allWidgets = styleRulesCache->keys();
2940 styleSheetCache->remove(qApp);
2941 styleRulesCache->clear();
2942 hasStyleRuleCache->clear();
2943 renderRulesCache->clear();
2944 updateWidgets(allWidgets);
2945}
2946
2947void QStyleSheetStyle::unpolish(QWidget *w)
2948{
2949 if (!w || !w->testAttribute(Qt::WA_StyleSheet)) {
2950 baseStyle()->unpolish(w);
2951 return;
2952 }
2953
2954 styleRulesCache->remove(w);
2955 hasStyleRuleCache->remove(w);
2956 renderRulesCache->remove(w);
2957 styleSheetCache->remove(w);
2958 unsetPalette(w);
2959 w->setProperty("_q_stylesheet_minw", QVariant());
2960 w->setProperty("_q_stylesheet_minh", QVariant());
2961 w->setProperty("_q_stylesheet_maxw", QVariant());
2962 w->setProperty("_q_stylesheet_maxh", QVariant());
2963 w->setAttribute(Qt::WA_StyleSheet, false);
2964 QObject::disconnect(w, 0, this, 0);
2965#ifndef QT_NO_SCROLLAREA
2966 if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(w)) {
2967 QObject::disconnect(sa->horizontalScrollBar(), SIGNAL(valueChanged(int)),
2968 sa, SLOT(update()));
2969 QObject::disconnect(sa->verticalScrollBar(), SIGNAL(valueChanged(int)),
2970 sa, SLOT(update()));
2971 }
2972#endif
2973#ifndef QT_NO_PROGRESSBAR
2974 if (QProgressBar *pb = qobject_cast<QProgressBar *>(w))
2975 QWindowsStyle::unpolish(pb);
2976#endif
2977 baseStyle()->unpolish(w);
2978}
2979
2980void QStyleSheetStyle::unpolish(QApplication *app)
2981{
2982 baseStyle()->unpolish(app);
2983 RECURSION_GUARD(return)
2984 styleRulesCache->clear();
2985 hasStyleRuleCache->clear();
2986 renderRulesCache->clear();
2987 styleSheetCache->remove(qApp);
2988}
2989
2990#ifndef QT_NO_TABBAR
2991inline static bool verticalTabs(QTabBar::Shape shape)
2992{
2993 return shape == QTabBar::RoundedWest
2994 || shape == QTabBar::RoundedEast
2995 || shape == QTabBar::TriangularWest
2996 || shape == QTabBar::TriangularEast;
2997}
2998#endif // QT_NO_TABBAR
2999
3000void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
3001 const QWidget *w) const
3002{
3003 RECURSION_GUARD(baseStyle()->drawComplexControl(cc, opt, p, w); return)
3004
3005 QRenderRule rule = renderRule(w, opt);
3006
3007 switch (cc) {
3008 case CC_ComboBox:
3009 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3010 QStyleOptionComboBox cmbOpt(*cmb);
3011 cmbOpt.rect = rule.borderRect(opt->rect);
3012 if (rule.hasNativeBorder()) {
3013 rule.drawBackgroundImage(p, cmbOpt.rect);
3014 rule.configurePalette(&cmbOpt.palette, QPalette::ButtonText, QPalette::Button);
3015 bool customDropDown = (opt->subControls & QStyle::SC_ComboBoxArrow)
3016 && hasStyleRule(w, PseudoElement_ComboBoxDropDown);
3017 if (customDropDown)
3018 cmbOpt.subControls &= ~QStyle::SC_ComboBoxArrow;
3019 if (rule.baseStyleCanDraw()) {
3020 baseStyle()->drawComplexControl(cc, &cmbOpt, p, w);
3021 } else {
3022 QWindowsStyle::drawComplexControl(cc, &cmbOpt, p, w);
3023 }
3024 if (!customDropDown)
3025 return;
3026 } else {
3027 rule.drawRule(p, opt->rect);
3028 }
3029
3030 if (opt->subControls & QStyle::SC_ComboBoxArrow) {
3031 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
3032 if (subRule.hasDrawable()) {
3033 QRect r = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow, w);
3034 subRule.drawRule(p, r);
3035 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_ComboBoxArrow);
3036 r = positionRect(w, subRule, subRule2, PseudoElement_ComboBoxArrow, r, opt->direction);
3037 subRule2.drawRule(p, r);
3038 } else {
3039 cmbOpt.subControls = QStyle::SC_ComboBoxArrow;
3040 QWindowsStyle::drawComplexControl(cc, &cmbOpt, p, w);
3041 }
3042 }
3043
3044 return;
3045 }
3046 break;
3047
3048#ifndef QT_NO_SPINBOX
3049 case CC_SpinBox:
3050 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
3051 QStyleOptionSpinBox spinOpt(*spin);
3052 rule.configurePalette(&spinOpt.palette, QPalette::ButtonText, QPalette::Button);
3053 spinOpt.rect = rule.borderRect(opt->rect);
3054 bool customUp = true, customDown = true;
3055 QRenderRule upRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
3056 QRenderRule downRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
3057 bool upRuleMatch = upRule.hasGeometry();
3058 bool downRuleMatch = downRule.hasGeometry();
3059 if (rule.hasNativeBorder() && !upRuleMatch && !downRuleMatch) {
3060 rule.drawBackgroundImage(p, spinOpt.rect);
3061 customUp = (opt->subControls & QStyle::SC_SpinBoxUp)
3062 && hasStyleRule(w, PseudoElement_SpinBoxUpButton);
3063 if (customUp)
3064 spinOpt.subControls &= ~QStyle::SC_SpinBoxUp;
3065 customDown = (opt->subControls & QStyle::SC_SpinBoxDown)
3066 && hasStyleRule(w, PseudoElement_SpinBoxDownButton);
3067 if (customDown)
3068 spinOpt.subControls &= ~QStyle::SC_SpinBoxDown;
3069 if (rule.baseStyleCanDraw()) {
3070 baseStyle()->drawComplexControl(cc, &spinOpt, p, w);
3071 } else {
3072 QWindowsStyle::drawComplexControl(cc, &spinOpt, p, w);
3073 }
3074 if (!customUp && !customDown)
3075 return;
3076 } else {
3077 rule.drawRule(p, opt->rect);
3078 }
3079
3080 if ((opt->subControls & QStyle::SC_SpinBoxUp) && customUp) {
3081 QRenderRule subRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
3082 if (subRule.hasDrawable()) {
3083 QRect r = subControlRect(CC_SpinBox, opt, SC_SpinBoxUp, w);
3084 subRule.drawRule(p, r);
3085 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SpinBoxUpArrow);
3086 r = positionRect(w, subRule, subRule2, PseudoElement_SpinBoxUpArrow, r, opt->direction);
3087 subRule2.drawRule(p, r);
3088 } else {
3089 spinOpt.subControls = QStyle::SC_SpinBoxUp;
3090 QWindowsStyle::drawComplexControl(cc, &spinOpt, p, w);
3091 }
3092 }
3093
3094 if ((opt->subControls & QStyle::SC_SpinBoxDown) && customDown) {
3095 QRenderRule subRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
3096 if (subRule.hasDrawable()) {
3097 QRect r = subControlRect(CC_SpinBox, opt, SC_SpinBoxDown, w);
3098 subRule.drawRule(p, r);
3099 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SpinBoxDownArrow);
3100 r = positionRect(w, subRule, subRule2, PseudoElement_SpinBoxDownArrow, r, opt->direction);
3101 subRule2.drawRule(p, r);
3102 } else {
3103 spinOpt.subControls = QStyle::SC_SpinBoxDown;
3104 QWindowsStyle::drawComplexControl(cc, &spinOpt, p, w);
3105 }
3106 }
3107 return;
3108 }
3109 break;
3110#endif // QT_NO_SPINBOX
3111
3112 case CC_GroupBox:
3113 if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
3114
3115 QRect labelRect, checkBoxRect, titleRect, frameRect;
3116 bool hasTitle = (gb->subControls & QStyle::SC_GroupBoxCheckBox) || !gb->text.isEmpty();
3117
3118 if (!rule.hasDrawable() && (!hasTitle || !hasStyleRule(w, PseudoElement_GroupBoxTitle))
3119 && !hasStyleRule(w, PseudoElement_Indicator) && !rule.hasBox() && !rule.hasFont && !rule.hasPalette()) {
3120 // let the native style draw the combobox if there is no style for it.
3121 break;
3122 }
3123 rule.drawBackground(p, opt->rect);
3124
3125 QRenderRule titleRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
3126 bool clipSet = false;
3127
3128 if (hasTitle) {
3129 labelRect = subControlRect(CC_GroupBox, opt, SC_GroupBoxLabel, w);
3130 //Some native style (such as mac) may return a too small rectangle (because they use smaller fonts), so we may need to expand it a little bit.
3131 labelRect.setSize(labelRect.size().expandedTo(ParentStyle::subControlRect(CC_GroupBox, opt, SC_GroupBoxLabel, w).size()));
3132 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
3133 checkBoxRect = subControlRect(CC_GroupBox, opt, SC_GroupBoxCheckBox, w);
3134 titleRect = titleRule.boxRect(checkBoxRect.united(labelRect));
3135 } else {
3136 titleRect = titleRule.boxRect(labelRect);
3137 }
3138 if (!titleRule.hasBackground() || !titleRule.background()->isTransparent()) {
3139 clipSet = true;
3140 p->save();
3141 p->setClipRegion(QRegion(opt->rect) - titleRect);
3142 }
3143 }
3144
3145 frameRect = subControlRect(CC_GroupBox, opt, SC_GroupBoxFrame, w);
3146 QStyleOptionFrameV2 frame;
3147 frame.QStyleOption::operator=(*gb);
3148 frame.features = gb->features;
3149 frame.lineWidth = gb->lineWidth;
3150 frame.midLineWidth = gb->midLineWidth;
3151 frame.rect = frameRect;
3152 drawPrimitive(PE_FrameGroupBox, &frame, p, w);
3153
3154 if (clipSet)
3155 p->restore();
3156
3157 // draw background and frame of the title
3158 if (hasTitle)
3159 titleRule.drawRule(p, titleRect);
3160
3161 // draw the indicator
3162 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
3163 QStyleOptionButton box;
3164 box.QStyleOption::operator=(*gb);
3165 box.rect = checkBoxRect;
3166 drawPrimitive(PE_IndicatorCheckBox, &box, p, w);
3167 }
3168
3169 // draw the text
3170 if (!gb->text.isEmpty()) {
3171 int alignment = int(Qt::AlignCenter | Qt::TextShowMnemonic);
3172 if (!styleHint(QStyle::SH_UnderlineShortcut, opt, w)) {
3173 alignment |= Qt::TextHideMnemonic;
3174 }
3175
3176 QPalette pal = gb->palette;
3177 if (gb->textColor.isValid())
3178 pal.setColor(QPalette::WindowText, gb->textColor);
3179 titleRule.configurePalette(&pal, QPalette::WindowText, QPalette::Window);
3180 drawItemText(p, labelRect, alignment, pal, gb->state & State_Enabled,
3181 gb->text, QPalette::WindowText);
3182 }
3183
3184 return;
3185 }
3186 break;
3187
3188 case CC_ToolButton:
3189 if (const QStyleOptionToolButton *tool = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3190 QStyleOptionToolButton toolOpt(*tool);
3191 rule.configurePalette(&toolOpt.palette, QPalette::ButtonText, QPalette::Button);
3192 toolOpt.rect = rule.borderRect(opt->rect);
3193 bool customArrow = (tool->features & (QStyleOptionToolButton::HasMenu | QStyleOptionToolButton::MenuButtonPopup));
3194 bool customDropDown = tool->features & QStyleOptionToolButton::MenuButtonPopup;
3195 if (rule.hasNativeBorder()) {
3196 if (tool->subControls & SC_ToolButton) {
3197 //in some case (eg. the button is "auto raised") the style doesn't draw the background
3198 //so we need to draw the background.
3199 // use the same condition as in QCommonStyle
3200 State bflags = tool->state & ~State_Sunken;
3201 if (bflags & State_AutoRaise && (!(bflags & State_MouseOver) || !(bflags & State_Enabled)))
3202 bflags &= ~State_Raised;
3203 if (tool->state & State_Sunken && tool->activeSubControls & SC_ToolButton)
3204 bflags |= State_Sunken;
3205 if (!(bflags & (State_Sunken | State_On | State_Raised)))
3206 rule.drawBackground(p, toolOpt.rect);
3207 }
3208 customArrow = customArrow && hasStyleRule(w, PseudoElement_ToolButtonDownArrow);
3209 if (customArrow)
3210 toolOpt.features &= ~QStyleOptionToolButton::HasMenu;
3211 customDropDown = customDropDown && hasStyleRule(w, PseudoElement_ToolButtonMenu);
3212 if (customDropDown)
3213 toolOpt.subControls &= ~QStyle::SC_ToolButtonMenu;
3214
3215 if (rule.baseStyleCanDraw() && !(tool->features & QStyleOptionToolButton::Arrow)) {
3216 baseStyle()->drawComplexControl(cc, &toolOpt, p, w);
3217 } else {
3218 QWindowsStyle::drawComplexControl(cc, &toolOpt, p, w);
3219 }
3220
3221 if (!customArrow && !customDropDown)
3222 return;
3223 } else {
3224 rule.drawRule(p, opt->rect);
3225 toolOpt.rect = rule.contentsRect(opt->rect);
3226 if (rule.hasFont)
3227 toolOpt.font = rule.font;
3228 drawControl(CE_ToolButtonLabel, &toolOpt, p, w);
3229 }
3230
3231 QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
3232 QRect r = subControlRect(CC_ToolButton, opt, QStyle::SC_ToolButtonMenu, w);
3233 if (customDropDown) {
3234 if (opt->subControls & QStyle::SC_ToolButtonMenu) {
3235 if (subRule.hasDrawable()) {
3236 subRule.drawRule(p, r);
3237 } else {
3238 toolOpt.rect = r;
3239 baseStyle()->drawPrimitive(PE_IndicatorButtonDropDown, &toolOpt, p, w);
3240 }
3241 }
3242 }
3243
3244 if (customArrow) {
3245 QRenderRule subRule2 = customDropDown ? renderRule(w, opt, PseudoElement_ToolButtonMenuArrow)
3246 : renderRule(w, opt, PseudoElement_ToolButtonDownArrow);
3247 QRect r2 = customDropDown
3248 ? positionRect(w, subRule, subRule2, PseudoElement_ToolButtonMenuArrow, r, opt->direction)
3249 : positionRect(w, rule, subRule2, PseudoElement_ToolButtonDownArrow, opt->rect, opt->direction);
3250 if (subRule2.hasDrawable()) {
3251 subRule2.drawRule(p, r2);
3252 } else {
3253 toolOpt.rect = r2;
3254 baseStyle()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &toolOpt, p, w);
3255 }
3256 }
3257
3258 return;
3259 }
3260 break;
3261
3262#ifndef QT_NO_SCROLLBAR
3263 case CC_ScrollBar:
3264 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3265 QStyleOptionSlider sbOpt(*sb);
3266 if (!rule.hasDrawable()) {
3267 sbOpt.rect = rule.borderRect(opt->rect);
3268 rule.drawBackgroundImage(p, opt->rect);
3269 baseStyle()->drawComplexControl(cc, &sbOpt, p, w);
3270 } else {
3271 rule.drawRule(p, opt->rect);
3272 QWindowsStyle::drawComplexControl(cc, opt, p, w);
3273 }
3274 return;
3275 }
3276 break;
3277#endif // QT_NO_SCROLLBAR
3278
3279#ifndef QT_NO_SLIDER
3280 case CC_Slider:
3281 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3282 rule.drawRule(p, opt->rect);
3283
3284 QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderGroove);
3285 if (!subRule.hasDrawable()) {
3286 baseStyle()->drawComplexControl(cc, slider, p, w);
3287 return;
3288 }
3289
3290 QRect gr = subControlRect(cc, opt, SC_SliderGroove, w);
3291 if (slider->subControls & SC_SliderGroove) {
3292 subRule.drawRule(p, gr);
3293 }
3294
3295 if (slider->subControls & SC_SliderHandle) {
3296 QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderHandle);
3297 QRect hr = subControlRect(cc, opt, SC_SliderHandle, w);
3298
3299 QRenderRule subRule1 = renderRule(w, opt, PseudoElement_SliderSubPage);
3300 if (subRule1.hasDrawable()) {
3301 QRect r(gr.topLeft(),
3302 slider->orientation == Qt::Horizontal
3303 ? QPoint(hr.x()+hr.width()/2, gr.y()+gr.height())
3304 : QPoint(gr.x()+gr.width(), hr.y()+hr.height()/2));
3305 subRule1.drawRule(p, r);
3306 }
3307
3308 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SliderAddPage);
3309 if (subRule2.hasDrawable()) {
3310 QRect r(slider->orientation == Qt::Horizontal
3311 ? QPoint(hr.x()+hr.width()/2+1, gr.y())
3312 : QPoint(gr.x(), hr.y()+hr.height()/2+1),
3313 gr.bottomRight());
3314 subRule2.drawRule(p, r);
3315 }
3316
3317 subRule.drawRule(p, subRule.boxRect(hr, Margin));
3318 }
3319
3320 if (slider->subControls & SC_SliderTickmarks) {
3321 // TODO...
3322 }
3323
3324 return;
3325 }
3326 break;
3327#endif // QT_NO_SLIDER
3328
3329 case CC_MdiControls:
3330 if (hasStyleRule(w, PseudoElement_MdiCloseButton)
3331 || hasStyleRule(w, PseudoElement_MdiNormalButton)
3332 || hasStyleRule(w, PseudoElement_MdiMinButton)) {
3333 QList<QVariant> layout = rule.styleHint(QLatin1String("button-layout")).toList();
3334 if (layout.isEmpty())
3335 layout = subControlLayout(QLatin1String("mNX"));
3336
3337 QStyleOptionComplex optCopy(*opt);
3338 optCopy.subControls = 0;
3339 for (int i = 0; i < layout.count(); i++) {
3340 int layoutButton = layout[i].toInt();
3341 if (layoutButton < PseudoElement_MdiCloseButton
3342 || layoutButton > PseudoElement_MdiNormalButton)
3343 continue;
3344 QStyle::SubControl control = knownPseudoElements[layoutButton].subControl;
3345 if (!(opt->subControls & control))
3346 continue;
3347 QRenderRule subRule = renderRule(w, opt, layoutButton);
3348 if (subRule.hasDrawable()) {
3349 QRect rect = subRule.boxRect(subControlRect(CC_MdiControls, opt, control, w), Margin);
3350 subRule.drawRule(p, rect);
3351 QIcon icon = standardIcon(subControlIcon(layoutButton));
3352 icon.paint(p, subRule.contentsRect(rect), Qt::AlignCenter);
3353 } else {
3354 optCopy.subControls |= control;
3355 }
3356 }
3357
3358 if (optCopy.subControls)
3359 baseStyle()->drawComplexControl(CC_MdiControls, &optCopy, p, w);
3360 return;
3361 }
3362 break;
3363
3364 case CC_TitleBar:
3365 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
3366 QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
3367 if (!subRule.hasDrawable() && !subRule.hasBox() && !subRule.hasBorder())
3368 break;
3369 subRule.drawRule(p, opt->rect);
3370 QHash<QStyle::SubControl, QRect> layout = titleBarLayout(w, tb);
3371
3372 QRect ir;
3373 ir = layout[SC_TitleBarLabel];
3374 if (ir.isValid()) {
3375 if (subRule.hasPalette())
3376 p->setPen(subRule.palette()->foreground.color());
3377 p->fillRect(ir, Qt::white);
3378 p->drawText(ir.x(), ir.y(), ir.width(), ir.height(), Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
3379 }
3380
3381 QPixmap pm;
3382
3383 ir = layout[SC_TitleBarSysMenu];
3384 if (ir.isValid()) {
3385 QRenderRule subSubRule = renderRule(w, opt, PseudoElement_TitleBarSysMenu);
3386 subSubRule.drawRule(p, ir);
3387 ir = subSubRule.contentsRect(ir);
3388 if (!tb->icon.isNull()) {
3389 tb->icon.paint(p, ir);
3390 } else {
3391 int iconSize = pixelMetric(PM_SmallIconSize, tb, w);
3392 pm = standardIcon(SP_TitleBarMenuButton, 0, w).pixmap(iconSize, iconSize);
3393 drawItemPixmap(p, ir, Qt::AlignCenter, pm);
3394 }
3395 }
3396
3397 ir = layout[SC_TitleBarCloseButton];
3398 if (ir.isValid()) {
3399 QRenderRule subSubRule = renderRule(w, opt, PseudoElement_TitleBarCloseButton);
3400 subSubRule.drawRule(p, ir);
3401
3402 QSize sz = subSubRule.contentsRect(ir).size();
3403 if ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool)
3404 pm = standardIcon(SP_DockWidgetCloseButton, 0, w).pixmap(sz);
3405 else
3406 pm = standardIcon(SP_TitleBarCloseButton, 0, w).pixmap(sz);
3407 drawItemPixmap(p, ir, Qt::AlignCenter, pm);
3408 }
3409
3410 int pes[] = {
3411 PseudoElement_TitleBarMaxButton,
3412 PseudoElement_TitleBarMinButton,
3413 PseudoElement_TitleBarNormalButton,
3414 PseudoElement_TitleBarShadeButton,
3415 PseudoElement_TitleBarUnshadeButton,
3416 PseudoElement_TitleBarContextHelpButton
3417 };
3418
3419 for (unsigned int i = 0; i < sizeof(pes)/sizeof(int); i++) {
3420 int pe = pes[i];
3421 QStyle::SubControl sc = knownPseudoElements[pe].subControl;
3422 ir = layout[sc];
3423 if (!ir.isValid())
3424 continue;
3425 QRenderRule subSubRule = renderRule(w, opt, pe);
3426 subSubRule.drawRule(p, ir);
3427 pm = standardIcon(subControlIcon(pe), 0, w).pixmap(subSubRule.contentsRect(ir).size());
3428 drawItemPixmap(p, ir, Qt::AlignCenter, pm);
3429 }
3430
3431 return;
3432 }
3433 break;
3434
3435
3436 default:
3437 break;
3438 }
3439
3440 baseStyle()->drawComplexControl(cc, opt, p, w);
3441}
3442
3443void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p,
3444 const QWidget *w) const
3445{
3446 RECURSION_GUARD(baseStyle()->drawControl(ce, opt, p, w); return)
3447
3448 QRenderRule rule = renderRule(w, opt);
3449 int pe1 = PseudoElement_None, pe2 = PseudoElement_None;
3450 bool fallback = false;
3451
3452 switch (ce) {
3453 case CE_ToolButtonLabel:
3454 if (const QStyleOptionToolButton *btn = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3455 if (rule.hasBox() || btn->features & QStyleOptionToolButton::Arrow) {
3456 QCommonStyle::drawControl(ce, opt, p, w);
3457 } else {
3458 QStyleOptionToolButton butOpt(*btn);
3459 rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3460 baseStyle()->drawControl(ce, &butOpt, p, w);
3461 }
3462 return;
3463 }
3464 break;
3465
3466 case CE_PushButton:
3467 ParentStyle::drawControl(ce, opt, p, w);
3468 return;
3469
3470 case CE_PushButtonBevel:
3471 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3472 QStyleOptionButton btnOpt(*btn);
3473 btnOpt.rect = rule.borderRect(opt->rect);
3474 if (rule.hasNativeBorder()) {
3475 rule.drawBackgroundImage(p, btnOpt.rect);
3476 rule.configurePalette(&btnOpt.palette, QPalette::ButtonText, QPalette::Button);
3477 bool customMenu = (btn->features & QStyleOptionButton::HasMenu
3478 && hasStyleRule(w, PseudoElement_PushButtonMenuIndicator));
3479 if (customMenu)
3480 btnOpt.features &= ~QStyleOptionButton::HasMenu;
3481 if (rule.baseStyleCanDraw()) {
3482 baseStyle()->drawControl(ce, &btnOpt, p, w);
3483 } else {
3484 QWindowsStyle::drawControl(ce, &btnOpt, p, w);
3485 }
3486 if (!customMenu)
3487 return;
3488 } else {
3489 rule.drawRule(p, opt->rect);
3490 }
3491
3492 if (btn->features & QStyleOptionButton::HasMenu) {
3493 QRenderRule subRule = renderRule(w, opt, PseudoElement_PushButtonMenuIndicator);
3494 QRect ir = positionRect(w, rule, subRule, PseudoElement_PushButtonMenuIndicator, opt->rect, opt->direction);
3495 if (subRule.hasDrawable()) {
3496 subRule.drawRule(p, ir);
3497 } else {
3498 btnOpt.rect = ir;
3499 baseStyle()->drawPrimitive(PE_IndicatorArrowDown, &btnOpt, p, w);
3500 }
3501 }
3502 }
3503 return;
3504
3505 case CE_PushButtonLabel:
3506 if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3507 QStyleOptionButton butOpt(*button);
3508 rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3509 if (rule.hasPosition() && rule.position()->textAlignment != 0) {
3510 Qt::Alignment textAlignment = rule.position()->textAlignment;
3511 QRect textRect = button->rect;
3512 uint tf = Qt::AlignVCenter | Qt::TextShowMnemonic;
3513 if (!styleHint(SH_UnderlineShortcut, button, w))
3514 tf |= Qt::TextHideMnemonic;
3515 if (!button->icon.isNull()) {
3516 //Group both icon and text
3517 QRect iconRect;
3518 QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
3519 if (mode == QIcon::Normal && button->state & State_HasFocus)
3520 mode = QIcon::Active;
3521 QIcon::State state = QIcon::Off;
3522 if (button->state & State_On)
3523 state = QIcon::On;
3524
3525 QPixmap pixmap = button->icon.pixmap(button->iconSize, mode, state);
3526 int labelWidth = pixmap.width();
3527 int labelHeight = pixmap.height();
3528 int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
3529 int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width();
3530 if (!button->text.isEmpty())
3531 labelWidth += (textWidth + iconSpacing);
3532
3533 //Determine label alignment:
3534 if (textAlignment & Qt::AlignLeft) { /*left*/
3535 iconRect = QRect(textRect.x(), textRect.y() + (textRect.height() - labelHeight) / 2,
3536 pixmap.width(), pixmap.height());
3537 } else if (textAlignment & Qt::AlignHCenter) { /* center */
3538 iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
3539 textRect.y() + (textRect.height() - labelHeight) / 2,
3540 pixmap.width(), pixmap.height());
3541 } else { /*right*/
3542 iconRect = QRect(textRect.x() + textRect.width() - labelWidth,
3543 textRect.y() + (textRect.height() - labelHeight) / 2,
3544 pixmap.width(), pixmap.height());
3545 }
3546
3547 iconRect = visualRect(button->direction, textRect, iconRect);
3548
3549 tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead
3550
3551 if (button->direction == Qt::RightToLeft)
3552 textRect.setRight(iconRect.left() - iconSpacing);
3553 else
3554 textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing);
3555
3556 if (button->state & (State_On | State_Sunken))
3557 iconRect.translate(pixelMetric(PM_ButtonShiftHorizontal, opt, w),
3558 pixelMetric(PM_ButtonShiftVertical, opt, w));
3559 p->drawPixmap(iconRect, pixmap);
3560 } else {
3561 tf |= textAlignment;
3562 }
3563 if (button->state & (State_On | State_Sunken))
3564 textRect.translate(pixelMetric(PM_ButtonShiftHorizontal, opt, w),
3565 pixelMetric(PM_ButtonShiftVertical, opt, w));
3566
3567 if (button->features & QStyleOptionButton::HasMenu) {
3568 int indicatorSize = pixelMetric(PM_MenuButtonIndicator, button, w);
3569 if (button->direction == Qt::LeftToRight)
3570 textRect = textRect.adjusted(0, 0, -indicatorSize, 0);
3571 else
3572 textRect = textRect.adjusted(indicatorSize, 0, 0, 0);
3573 }
3574 drawItemText(p, textRect, tf, butOpt.palette, (button->state & State_Enabled),
3575 button->text, QPalette::ButtonText);
3576 } else {
3577 ParentStyle::drawControl(ce, &butOpt, p, w);
3578 }
3579 }
3580 return;
3581
3582 case CE_RadioButton:
3583 case CE_CheckBox:
3584 rule.drawRule(p, opt->rect);
3585 ParentStyle::drawControl(ce, opt, p, w);
3586 return;
3587
3588 case CE_RadioButtonLabel:
3589 case CE_CheckBoxLabel:
3590 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3591 QStyleOptionButton butOpt(*btn);
3592 rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3593 ParentStyle::drawControl(ce, &butOpt, p, w);
3594 }
3595 return;
3596
3597 case CE_Splitter:
3598 pe1 = PseudoElement_SplitterHandle;
3599 break;
3600
3601 case CE_ToolBar:
3602 if (rule.hasBackground()) {
3603 rule.drawBackground(p, opt->rect);
3604 }
3605 if (rule.hasBorder()) {
3606 rule.drawBorder(p, rule.borderRect(opt->rect));
3607 } else {
3608#ifndef QT_NO_TOOLBAR
3609 if (const QStyleOptionToolBar *tb = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
3610 QStyleOptionToolBar newTb(*tb);
3611 newTb.rect = rule.borderRect(opt->rect);
3612 baseStyle()->drawControl(ce, &newTb, p, w);
3613 }
3614#endif // QT_NO_TOOLBAR
3615 }
3616 return;
3617
3618 case CE_MenuEmptyArea:
3619 case CE_MenuBarEmptyArea:
3620 if (rule.hasDrawable()) {
3621 return;
3622 }
3623 break;
3624
3625 case CE_MenuTearoff:
3626 case CE_MenuScroller:
3627 if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3628 QStyleOptionMenuItem mi(*m);
3629 int pe = ce == CE_MenuTearoff ? PseudoElement_MenuTearoff : PseudoElement_MenuScroller;
3630 QRenderRule subRule = renderRule(w, opt, pe);
3631 mi.rect = subRule.contentsRect(opt->rect);
3632 rule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3633 subRule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3634
3635 if (subRule.hasDrawable()) {
3636 subRule.drawRule(p, opt->rect);
3637 } else {
3638 baseStyle()->drawControl(ce, &mi, p, w);
3639 }
3640 }
3641 return;
3642
3643 case CE_MenuItem:
3644 if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3645 QStyleOptionMenuItem mi(*m);
3646
3647 int pseudo = (mi.menuItemType == QStyleOptionMenuItem::Separator) ? PseudoElement_MenuSeparator : PseudoElement_Item;
3648 QRenderRule subRule = renderRule(w, opt, pseudo);
3649 mi.rect = subRule.contentsRect(opt->rect);
3650 rule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3651 rule.configurePalette(&mi.palette, QPalette::HighlightedText, QPalette::Highlight);
3652 subRule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3653 subRule.configurePalette(&mi.palette, QPalette::HighlightedText, QPalette::Highlight);
3654 QFont oldFont = p->font();
3655 if (subRule.hasFont)
3656 p->setFont(subRule.font.resolve(p->font()));
3657
3658 // We fall back to drawing with the style sheet code whenever at least one of the
3659 // items are styled in an incompatible way, such as having a background image.
3660 QRenderRule allRules = renderRule(w, PseudoElement_Item, PseudoClass_Any);
3661
3662 if ((pseudo == PseudoElement_MenuSeparator) && subRule.hasDrawable()) {
3663 subRule.drawRule(p, opt->rect);
3664 } else if ((pseudo == PseudoElement_Item)
3665 && (allRules.hasBox() || allRules.hasBorder()
3666 || (allRules.background() && !allRules.background()->pixmap.isNull()))) {
3667 subRule.drawRule(p, opt->rect);
3668 if (subRule.hasBackground()) {
3669 mi.palette.setBrush(QPalette::Highlight, Qt::NoBrush);
3670 mi.palette.setBrush(QPalette::Button, Qt::NoBrush);
3671 } else {
3672 mi.palette.setBrush(QPalette::Highlight, mi.palette.brush(QPalette::Button));
3673 }
3674 mi.palette.setBrush(QPalette::HighlightedText, mi.palette.brush(QPalette::ButtonText));
3675
3676 bool checkable = mi.checkType != QStyleOptionMenuItem::NotCheckable;
3677 bool checked = checkable ? mi.checked : false;
3678
3679 bool dis = !(opt->state & QStyle::State_Enabled),
3680 act = opt->state & QStyle::State_Selected;
3681
3682 if (!mi.icon.isNull()) {
3683 QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
3684 if (act && !dis)
3685 mode = QIcon::Active;
3686 QPixmap pixmap;
3687 if (checked)
3688 pixmap = mi.icon.pixmap(pixelMetric(PM_SmallIconSize), mode, QIcon::On);
3689 else
3690 pixmap = mi.icon.pixmap(pixelMetric(PM_SmallIconSize), mode);
3691 int pixw = pixmap.width();
3692 int pixh = pixmap.height();
3693 QRenderRule iconRule = renderRule(w, opt, PseudoElement_MenuIcon);
3694 if (!iconRule.hasGeometry()) {
3695 iconRule.geo = new QStyleSheetGeometryData(pixw, pixh, pixw, pixh, -1, -1);
3696 } else {
3697 iconRule.geo->width = pixw;
3698 iconRule.geo->height = pixh;
3699 }
3700 QRect iconRect = positionRect(w, subRule, iconRule, PseudoElement_MenuIcon, opt->rect, opt->direction);
3701 iconRule.drawRule(p, iconRect);
3702 QRect pmr(0, 0, pixw, pixh);
3703 pmr.moveCenter(iconRect.center());
3704 p->drawPixmap(pmr.topLeft(), pixmap);
3705 } else if (checkable) {
3706 QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark);
3707 if (subSubRule.hasDrawable() || checked) {
3708 QStyleOptionMenuItem newMi = mi;
3709 newMi.rect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction);
3710 drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w);
3711 }
3712 }
3713
3714 QRect textRect = subRule.contentsRect(opt->rect);
3715 textRect.setWidth(textRect.width() - mi.tabWidth);
3716 QString s = mi.text;
3717 p->setPen(mi.palette.buttonText().color());
3718 if (!s.isEmpty()) {
3719 int text_flags = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
3720 if (!styleHint(SH_UnderlineShortcut, &mi, w))
3721 text_flags |= Qt::TextHideMnemonic;
3722 int t = s.indexOf(QLatin1Char('\t'));
3723 if (t >= 0) {
3724 QRect vShortcutRect = visualRect(opt->direction, mi.rect,
3725 QRect(textRect.topRight(), QPoint(mi.rect.right(), textRect.bottom())));
3726 p->drawText(vShortcutRect, text_flags, s.mid(t + 1));
3727 s = s.left(t);
3728 }
3729 p->drawText(textRect, text_flags, s.left(t));
3730 }
3731
3732 if (mi.menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
3733 PrimitiveElement arrow = (opt->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
3734 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_MenuRightArrow);
3735 mi.rect = positionRect(w, subRule, subRule2, PseudoElement_MenuRightArrow, opt->rect, mi.direction);
3736 drawPrimitive(arrow, &mi, p, w);
3737 }
3738 } else if (hasStyleRule(w, PseudoElement_MenuCheckMark)) {
3739 QWindowsStyle::drawControl(ce, &mi, p, w);
3740 } else {
3741 if (rule.hasDrawable() && !subRule.hasDrawable() && !(opt->state & QStyle::State_Selected)) {
3742 mi.palette.setColor(QPalette::Window, Qt::transparent);
3743 mi.palette.setColor(QPalette::Button, Qt::transparent);
3744 }
3745 if (rule.baseStyleCanDraw() && subRule.baseStyleCanDraw()) {
3746 baseStyle()->drawControl(ce, &mi, p, w);
3747 } else {
3748 ParentStyle::drawControl(ce, &mi, p, w);
3749 }
3750 }
3751
3752 if (subRule.hasFont)
3753 p->setFont(oldFont);
3754
3755 return;
3756 }
3757 return;
3758
3759 case CE_MenuBarItem:
3760 if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3761 QStyleOptionMenuItem mi(*m);
3762 QRenderRule subRule = renderRule(w, opt, PseudoElement_Item);
3763 mi.rect = subRule.contentsRect(opt->rect);
3764 rule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3765 subRule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3766
3767 if (subRule.hasDrawable()) {
3768 subRule.drawRule(p, opt->rect);
3769 QCommonStyle::drawControl(ce, &mi, p, w);
3770 } else {
3771 baseStyle()->drawControl(ce, &mi, p, w);
3772 }
3773 }
3774 return;
3775
3776#ifndef QT_NO_COMBOBOX
3777 case CE_ComboBoxLabel:
3778 if (!rule.hasBox())
3779 break;
3780 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3781 QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, w);
3782 p->save();
3783 p->setClipRect(editRect);
3784 if (!cb->currentIcon.isNull()) {
3785 int spacing = rule.hasBox() ? rule.box()->spacing : -1;
3786 if (spacing == -1)
3787 spacing = 6;
3788 QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
3789 QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode);
3790 QRect iconRect(editRect);
3791 iconRect.setWidth(cb->iconSize.width());
3792 iconRect = alignedRect(QApplication::layoutDirection(),
3793 Qt::AlignLeft | Qt::AlignVCenter,
3794 iconRect.size(), editRect);
3795 drawItemPixmap(p, iconRect, Qt::AlignCenter, pixmap);
3796
3797 if (cb->direction == Qt::RightToLeft)
3798 editRect.translate(-spacing - cb->iconSize.width(), 0);
3799 else
3800 editRect.translate(cb->iconSize.width() + spacing, 0);
3801 }
3802 if (!cb->currentText.isEmpty() && !cb->editable) {
3803 drawItemText(p, editRect.adjusted(0, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, cb->palette,
3804 cb->state & State_Enabled, cb->currentText);
3805 }
3806 p->restore();
3807 return;
3808 }
3809 break;
3810#endif // QT_NO_COMBOBOX
3811
3812 case CE_Header:
3813 if (hasStyleRule(w, PseudoElement_HeaderViewUpArrow)
3814 || hasStyleRule(w, PseudoElement_HeaderViewDownArrow)) {
3815 ParentStyle::drawControl(ce, opt, p, w);
3816 return;
3817 }
3818 if(hasStyleRule(w, PseudoElement_HeaderViewSection)) {
3819 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
3820 if (!subRule.hasNativeBorder() || !subRule.baseStyleCanDraw()
3821 || subRule.hasBackground() || subRule.hasPalette()) {
3822 ParentStyle::drawControl(ce, opt, p, w);
3823 return;
3824 }
3825 }
3826 break;
3827 case CE_HeaderSection:
3828 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3829 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
3830 if (subRule.hasNativeBorder()) {
3831 QStyleOptionHeader hdr(*header);
3832 subRule.configurePalette(&hdr.palette, QPalette::ButtonText, QPalette::Button);
3833
3834 if (subRule.baseStyleCanDraw()) {
3835 baseStyle()->drawControl(CE_HeaderSection, &hdr, p, w);
3836 } else {
3837 QWindowsStyle::drawControl(CE_HeaderSection, &hdr, p, w);
3838 }
3839 } else {
3840 subRule.drawRule(p, opt->rect);
3841 }
3842 return;
3843 }
3844 break;
3845
3846 case CE_HeaderLabel:
3847 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3848 QStyleOptionHeader hdr(*header);
3849 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
3850 subRule.configurePalette(&hdr.palette, QPalette::ButtonText, QPalette::Button);
3851 QFont oldFont = p->font();
3852 if (subRule.hasFont)
3853 p->setFont(subRule.font.resolve(p->font()));
3854 baseStyle()->drawControl(ce, &hdr, p, w);
3855 if (subRule.hasFont)
3856 p->setFont(oldFont);
3857 return;
3858 }
3859 break;
3860
3861 case CE_HeaderEmptyArea:
3862 if (rule.hasDrawable()) {
3863 return;
3864 }
3865 break;
3866
3867 case CE_ProgressBar:
3868 QWindowsStyle::drawControl(ce, opt, p, w);
3869 return;
3870
3871 case CE_ProgressBarGroove:
3872 if (!rule.hasNativeBorder()) {
3873 rule.drawRule(p, rule.boxRect(opt->rect, Margin));
3874 return;
3875 }
3876 break;
3877
3878 case CE_ProgressBarContents: {
3879 QRenderRule subRule = renderRule(w, opt, PseudoElement_ProgressBarChunk);
3880 if (subRule.hasDrawable()) {
3881 if (const QStyleOptionProgressBarV2 *pb = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(opt)) {
3882 p->save();
3883 p->setClipRect(pb->rect);
3884
3885 qint64 minimum = qint64(pb->minimum);
3886 qint64 maximum = qint64(pb->maximum);
3887 qint64 progress = qint64(pb->progress);
3888 bool vertical = (pb->orientation == Qt::Vertical);
3889 bool inverted = pb->invertedAppearance;
3890
3891 QTransform m;
3892 QRect rect = pb->rect;
3893 if (vertical) {
3894 rect = QRect(rect.y(), rect.x(), rect.height(), rect.width());
3895 m.rotate(90);
3896 m.translate(0, -(rect.height() + rect.y()*2));
3897 }
3898
3899 bool reverse = ((!vertical && (pb->direction == Qt::RightToLeft)) || vertical);
3900 if (inverted)
3901 reverse = !reverse;
3902 const bool indeterminate = pb->minimum == pb->maximum;
3903 qreal fillRatio = indeterminate ? 0.50 : qreal(progress - minimum)/(maximum - minimum);
3904 int fillWidth = int(rect.width() * fillRatio);
3905 int chunkWidth = fillWidth;
3906 if (subRule.hasContentsSize()) {
3907 QSize sz = subRule.size();
3908 chunkWidth = (opt->state & QStyle::State_Horizontal) ? sz.width() : sz.height();
3909 }
3910
3911 QRect r = rect;
3912 if (pb->minimum == 0 && pb->maximum == 0) {
3913 Q_D(const QWindowsStyle);
3914 int chunkCount = fillWidth/chunkWidth;
3915 int offset = (d->animateStep*8%rect.width());
3916 int x = reverse ? r.left() + r.width() - offset - chunkWidth : r.x() + offset;
3917 while (chunkCount > 0) {
3918 r.setRect(x, rect.y(), chunkWidth, rect.height());
3919 r = m.mapRect(QRectF(r)).toRect();
3920 subRule.drawRule(p, r);
3921 x += reverse ? -chunkWidth : chunkWidth;
3922 if (reverse ? x < rect.left() : x > rect.right())
3923 break;
3924 --chunkCount;
3925 }
3926
3927 r = rect;
3928 x = reverse ? r.right() - (r.left() - x - chunkWidth)
3929 : r.left() + (x - r.right() - chunkWidth);
3930 while (chunkCount > 0) {
3931 r.setRect(x, rect.y(), chunkWidth, rect.height());
3932 r = m.mapRect(QRectF(r)).toRect();
3933 subRule.drawRule(p, r);
3934 x += reverse ? -chunkWidth : chunkWidth;
3935 --chunkCount;
3936 };
3937 } else {
3938 int x = reverse ? r.left() + r.width() - chunkWidth : r.x();
3939
3940 for (int i = 0; i < ceil(qreal(fillWidth)/chunkWidth); ++i) {
3941 r.setRect(x, rect.y(), chunkWidth, rect.height());
3942 r = m.mapRect(QRectF(r)).toRect();
3943 subRule.drawRule(p, r);
3944 x += reverse ? -chunkWidth : chunkWidth;
3945 }
3946 }
3947
3948 p->restore();
3949 return;
3950 }
3951 }
3952 }
3953 break;
3954
3955 case CE_ProgressBarLabel:
3956 if (const QStyleOptionProgressBarV2 *pb = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(opt)) {
3957 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_ProgressBarChunk)) {
3958 drawItemText(p, pb->rect, pb->textAlignment | Qt::TextSingleLine, pb->palette,
3959 pb->state & State_Enabled, pb->text, QPalette::Text);
3960 } else {
3961 QStyleOptionProgressBarV2 pbCopy(*pb);
3962 rule.configurePalette(&pbCopy.palette, QPalette::HighlightedText, QPalette::Highlight);
3963 baseStyle()->drawControl(ce, &pbCopy, p, w);
3964 }
3965 return;
3966 }
3967 break;
3968
3969 case CE_SizeGrip:
3970 if (const QStyleOptionSizeGrip *sgOpt = qstyleoption_cast<const QStyleOptionSizeGrip *>(opt)) {
3971 if (rule.hasDrawable()) {
3972 rule.drawFrame(p, opt->rect);
3973 p->save();
3974 switch (sgOpt->corner) {
3975 case Qt::BottomRightCorner: break;
3976 case Qt::BottomLeftCorner: p->rotate(90); break;
3977 case Qt::TopLeftCorner: p->rotate(180); break;
3978 case Qt::TopRightCorner: p->rotate(270); break;
3979 default: break;
3980 }
3981 rule.drawImage(p, opt->rect);
3982 p->restore();
3983 } else {
3984 QStyleOptionSizeGrip sg(*sgOpt);
3985 sg.rect = rule.contentsRect(opt->rect);
3986 baseStyle()->drawControl(CE_SizeGrip, &sg, p, w);
3987 }
3988 return;
3989 }
3990 break;
3991
3992 case CE_ToolBoxTab:
3993 QWindowsStyle::drawControl(ce, opt, p, w);
3994 return;
3995
3996 case CE_ToolBoxTabShape: {
3997 QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolBoxTab);
3998 if (subRule.hasDrawable()) {
3999 subRule.drawRule(p, opt->rect);
4000 return;
4001 }
4002 }
4003 break;
4004
4005 case CE_ToolBoxTabLabel:
4006 if (const QStyleOptionToolBox *box = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
4007 QStyleOptionToolBox boxCopy(*box);
4008 QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolBoxTab);
4009 subRule.configurePalette(&boxCopy.palette, QPalette::ButtonText, QPalette::Button);
4010 QFont oldFont = p->font();
4011 if (subRule.hasFont)
4012 p->setFont(subRule.font);
4013 boxCopy.rect = subRule.contentsRect(opt->rect);
4014 QWindowsStyle::drawControl(ce, &boxCopy, p , w);
4015 if (subRule.hasFont)
4016 p->setFont(oldFont);
4017 return;
4018 }
4019 break;
4020
4021 case CE_ScrollBarAddPage:
4022 pe1 = PseudoElement_ScrollBarAddPage;
4023 break;
4024
4025 case CE_ScrollBarSubPage:
4026 pe1 = PseudoElement_ScrollBarSubPage;
4027 break;
4028
4029 case CE_ScrollBarAddLine:
4030 pe1 = PseudoElement_ScrollBarAddLine;
4031 pe2 = (opt->state & QStyle::State_Horizontal) ? PseudoElement_ScrollBarRightArrow : PseudoElement_ScrollBarDownArrow;
4032 fallback = true;
4033 break;
4034
4035 case CE_ScrollBarSubLine:
4036 pe1 = PseudoElement_ScrollBarSubLine;
4037 pe2 = (opt->state & QStyle::State_Horizontal) ? PseudoElement_ScrollBarLeftArrow : PseudoElement_ScrollBarUpArrow;
4038 fallback = true;
4039 break;
4040
4041 case CE_ScrollBarFirst:
4042 pe1 = PseudoElement_ScrollBarFirst;
4043 break;
4044
4045 case CE_ScrollBarLast:
4046 pe1 = PseudoElement_ScrollBarLast;
4047 break;
4048
4049 case CE_ScrollBarSlider:
4050 pe1 = PseudoElement_ScrollBarSlider;
4051 fallback = true;
4052 break;
4053
4054#ifndef QT_NO_ITEMVIEWS
4055 case CE_ItemViewItem:
4056 if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) {
4057 QRenderRule subRule = renderRule(w, opt, PseudoElement_ViewItem);
4058 if (subRule.hasDrawable() || hasStyleRule(w, PseudoElement_Indicator)) {
4059 QStyleOptionViewItemV4 optCopy(*vopt);
4060 subRule.configurePalette(&optCopy.palette, vopt->state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text,
4061 vopt->state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base);
4062 QWindowsStyle::drawControl(ce, &optCopy, p, w);
4063 } else {
4064 QStyleOptionViewItemV4 voptCopy(*vopt);
4065 subRule.configurePalette(&voptCopy.palette, QPalette::Text, QPalette::NoRole);
4066 baseStyle()->drawControl(ce, &voptCopy, p, w);
4067 }
4068 return;
4069 }
4070 break;
4071#endif // QT_NO_ITEMVIEWS
4072
4073#ifndef QT_NO_TABBAR
4074 case CE_TabBarTab:
4075 if (hasStyleRule(w, PseudoElement_TabBarTab)) {
4076 QWindowsStyle::drawControl(ce, opt, p, w);
4077 return;
4078 }
4079 break;
4080
4081 case CE_TabBarTabLabel:
4082 case CE_TabBarTabShape:
4083 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4084 QStyleOptionTabV3 tabCopy(*tab);
4085 QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTab);
4086 QRect r = positionRect(w, subRule, PseudoElement_TabBarTab, opt->rect, opt->direction);
4087 if (ce == CE_TabBarTabShape && subRule.hasDrawable()) {
4088 subRule.drawRule(p, r);
4089 return;
4090 }
4091 subRule.configurePalette(&tabCopy.palette, QPalette::WindowText, QPalette::Window);
4092 QFont oldFont = p->font();
4093 if (subRule.hasFont)
4094 p->setFont(subRule.font);
4095 if (subRule.hasBox()) {
4096 tabCopy.rect = ce == CE_TabBarTabShape ? subRule.borderRect(r)
4097 : subRule.contentsRect(r);
4098 QWindowsStyle::drawControl(ce, &tabCopy, p, w);
4099 } else {
4100 baseStyle()->drawControl(ce, &tabCopy, p, w);
4101 }
4102 if (subRule.hasFont)
4103 p->setFont(oldFont);
4104
4105 return;
4106 }
4107 break;
4108#endif // QT_NO_TABBAR
4109
4110 case CE_ColumnViewGrip:
4111 if (rule.hasDrawable()) {
4112 rule.drawRule(p, opt->rect);
4113 return;
4114 }
4115 break;
4116
4117 case CE_DockWidgetTitle:
4118 if (const QStyleOptionDockWidgetV2 *dwOpt = qstyleoption_cast<const QStyleOptionDockWidgetV2 *>(opt)) {
4119 QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetTitle);
4120 if (!subRule.hasDrawable() && !subRule.hasPosition())
4121 break;
4122 if (subRule.hasDrawable()) {
4123 subRule.drawRule(p, opt->rect);
4124 } else {
4125 QStyleOptionDockWidgetV2 dwCopy(*dwOpt);
4126 dwCopy.title = QString();
4127 baseStyle()->drawControl(ce, &dwCopy, p, w);
4128 }
4129
4130 if (!dwOpt->title.isEmpty()) {
4131 QRect r = opt->rect;
4132 if (dwOpt->verticalTitleBar) {
4133 QSize s = r.size();
4134 s.transpose();
4135 r.setSize(s);
4136
4137 p->save();
4138 p->translate(r.left(), r.top() + r.width());
4139 p->rotate(-90);
4140 p->translate(-r.left(), -r.top());
4141 }
4142
4143 Qt::Alignment alignment = 0;
4144 if (subRule.hasPosition())
4145 alignment = subRule.position()->textAlignment;
4146 if (alignment == 0)
4147 alignment = Qt::AlignLeft;
4148 drawItemText(p, subRule.contentsRect(opt->rect),
4149 alignment | Qt::TextShowMnemonic, dwOpt->palette,
4150 dwOpt->state & State_Enabled, dwOpt->title,
4151 QPalette::WindowText);
4152
4153 if (dwOpt->verticalTitleBar)
4154 p->restore();
4155 }
4156
4157 return;
4158 }
4159 break;
4160 case CE_ShapedFrame:
4161 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4162 if (rule.hasNativeBorder()) {
4163 QStyleOptionFrameV3 frmOpt(*frm);
4164 rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base);
4165 frmOpt.rect = rule.borderRect(frmOpt.rect);
4166 baseStyle()->drawControl(ce, &frmOpt, p, w);
4167 } else {
4168 rule.drawBorder(p, rule.borderRect(opt->rect));
4169 }
4170 }
4171 return;
4172
4173
4174 default:
4175 break;
4176 }
4177
4178 if (pe1 != PseudoElement_None) {
4179 QRenderRule subRule = renderRule(w, opt, pe1);
4180 if (subRule.bg != 0 || subRule.hasDrawable()) {
4181 //We test subRule.bg dirrectly because hasBackground() would return false for background:none.
4182 //But we still don't want the default drawning in that case (example for QScrollBar::add-page) (task 198926)
4183 subRule.drawRule(p, opt->rect);
4184 } else if (fallback) {
4185 QWindowsStyle::drawControl(ce, opt, p, w);
4186 pe2 = PseudoElement_None;
4187 } else {
4188 baseStyle()->drawControl(ce, opt, p, w);
4189 }
4190 if (pe2 != PseudoElement_None) {
4191 QRenderRule subSubRule = renderRule(w, opt, pe2);
4192 QRect r = positionRect(w, subRule, subSubRule, pe2, opt->rect, opt->direction);
4193 subSubRule.drawRule(p, r);
4194 }
4195 return;
4196 }
4197
4198 baseStyle()->drawControl(ce, opt, p, w);
4199}
4200
4201void QStyleSheetStyle::drawItemPixmap(QPainter *p, const QRect &rect, int alignment, const
4202 QPixmap &pixmap) const
4203{
4204 baseStyle()->drawItemPixmap(p, rect, alignment, pixmap);
4205}
4206
4207void QStyleSheetStyle::drawItemText(QPainter *painter, const QRect& rect, int alignment, const QPalette &pal,
4208 bool enabled, const QString& text, QPalette::ColorRole textRole) const
4209{
4210 baseStyle()->drawItemText(painter, rect, alignment, pal, enabled, text, textRole);
4211}
4212
4213void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
4214 const QWidget *w) const
4215{
4216 RECURSION_GUARD(baseStyle()->drawPrimitive(pe, opt, p, w); return)
4217
4218 int pseudoElement = PseudoElement_None;
4219 QRenderRule rule = renderRule(w, opt);
4220 QRect rect = opt->rect;
4221
4222 switch (pe) {
4223 case PE_PanelStatusBar:
4224 if (rule.hasDrawable()) {
4225 rule.drawRule(p, opt->rect);
4226 return;
4227 }
4228 break;
4229
4230 case PE_FrameStatusBar: {
4231 QRenderRule subRule = renderRule(w->parentWidget(), opt, PseudoElement_Item);
4232 if (subRule.hasDrawable()) {
4233 subRule.drawRule(p, opt->rect);
4234 return;
4235 }
4236 break;
4237 }
4238
4239 case PE_IndicatorArrowDown:
4240 pseudoElement = PseudoElement_DownArrow;
4241 break;
4242
4243 case PE_IndicatorRadioButton:
4244 pseudoElement = PseudoElement_ExclusiveIndicator;
4245 break;
4246
4247 case PE_IndicatorViewItemCheck:
4248 pseudoElement = PseudoElement_ViewItemIndicator;
4249 break;
4250
4251 case PE_IndicatorCheckBox:
4252 pseudoElement = PseudoElement_Indicator;
4253 break;
4254
4255 case PE_IndicatorHeaderArrow:
4256 if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4257 pseudoElement = hdr->sortIndicator == QStyleOptionHeader::SortUp
4258 ? PseudoElement_HeaderViewUpArrow
4259 : PseudoElement_HeaderViewDownArrow;
4260 }
4261 break;
4262
4263 case PE_PanelButtonTool:
4264 case PE_PanelButtonCommand:
4265 if (qobject_cast<const QAbstractButton *>(w) && rule.hasBackground() && rule.hasNativeBorder()) {
4266 //the window style will draw the borders
4267 ParentStyle::drawPrimitive(pe, opt, p, w);
4268 if (!rule.background()->pixmap.isNull() || rule.hasImage()) {
4269 rule.drawRule(p, rule.boxRect(opt->rect, QRenderRule::Margin).adjusted(1,1,-1,-1));
4270 }
4271 return;
4272 }
4273 if (!rule.hasNativeBorder()) {
4274 rule.drawRule(p, rule.boxRect(opt->rect, QRenderRule::Margin));
4275 return;
4276 }
4277 break;
4278
4279 case PE_IndicatorButtonDropDown: {
4280 QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
4281 if (!subRule.hasNativeBorder()) {
4282 rule.drawBorder(p, opt->rect);
4283 return;
4284 }
4285 break;
4286 }
4287
4288 case PE_FrameDefaultButton:
4289 if (rule.hasNativeBorder()) {
4290 if (rule.baseStyleCanDraw())
4291 break;
4292 QWindowsStyle::drawPrimitive(pe, opt, p, w);
4293 }
4294 return;
4295
4296 case PE_FrameWindow:
4297 case PE_FrameDockWidget:
4298 case PE_Frame:
4299 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4300 if (rule.hasNativeBorder()) {
4301 QStyleOptionFrameV2 frmOpt(*frm);
4302 rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base);
4303 if (!qstyleoption_cast<const QStyleOptionFrameV3 *>(opt)) //if it comes from CE_ShapedFrame, the margins are already sustracted
4304 frmOpt.rect = rule.borderRect(frmOpt.rect);
4305 baseStyle()->drawPrimitive(pe, &frmOpt, p, w);
4306 } else {
4307 rule.drawBorder(p, rule.borderRect(opt->rect));
4308 }
4309 }
4310 return;
4311
4312 case PE_PanelLineEdit:
4313 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4314#ifndef QT_NO_SPINBOX
4315 if (w && qobject_cast<const QAbstractSpinBox *>(w->parentWidget())) {
4316 QRenderRule spinboxRule = renderRule(w->parentWidget(), opt);
4317 if (!spinboxRule.hasNativeBorder() || !spinboxRule.baseStyleCanDraw())
4318 return;
4319 }
4320#endif
4321 if (rule.hasNativeBorder()) {
4322 QStyleOptionFrame frmOpt(*frm);
4323 rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base);
4324 frmOpt.rect = rule.borderRect(frmOpt.rect);
4325 if (rule.baseStyleCanDraw()) {
4326 rule.drawBackgroundImage(p, opt->rect);
4327 baseStyle()->drawPrimitive(pe, &frmOpt, p, w);
4328 } else {
4329 rule.drawBackground(p, opt->rect);
4330 if (frmOpt.lineWidth > 0)
4331 baseStyle()->drawPrimitive(PE_FrameLineEdit, &frmOpt, p, w);
4332 }
4333 } else {
4334 rule.drawRule(p, opt->rect);
4335 }
4336 }
4337 return;
4338
4339 case PE_Widget:
4340 if (!rule.hasBackground()) {
4341 QWidget *container = containerWidget(w);
4342 if (autoFillDisabledWidgets->contains(container)
4343 && (container == w || !renderRule(container, opt).hasBackground())) {
4344 //we do not have a background, but we disabled the autofillbackground anyway. so fill the background now.
4345 // (this may happen if we have rules like :focus)
4346 p->fillRect(opt->rect, opt->palette.brush(w->backgroundRole()));
4347 }
4348 break;
4349 }
4350
4351#ifndef QT_NO_SCROLLAREA
4352 if (const QAbstractScrollArea *sa = qobject_cast<const QAbstractScrollArea *>(w)) {
4353 const QAbstractScrollAreaPrivate *sap = sa->d_func();
4354 rule.drawBackground(p, opt->rect, sap->contentsOffset());
4355 } else
4356#endif
4357 {
4358 rule.drawBackground(p, opt->rect);
4359 }
4360
4361 return;
4362
4363 case PE_FrameMenu:
4364 case PE_PanelMenuBar:
4365 if (!rule.hasNativeBorder()) {
4366 rule.drawBorder(p, rule.borderRect(opt->rect));
4367 return;
4368 }
4369 break;
4370
4371 case PE_IndicatorToolBarSeparator:
4372 case PE_IndicatorToolBarHandle: {
4373 PseudoElement ps = pe == PE_IndicatorToolBarHandle ? PseudoElement_ToolBarHandle : PseudoElement_ToolBarSeparator;
4374 QRenderRule subRule = renderRule(w, opt, ps);
4375 if (subRule.hasDrawable()) {
4376 subRule.drawRule(p, opt->rect);
4377 return;
4378 }
4379 }
4380 break;
4381
4382 case PE_IndicatorMenuCheckMark:
4383 pseudoElement = PseudoElement_MenuCheckMark;
4384 break;
4385
4386 case PE_IndicatorArrowLeft:
4387 pseudoElement = PseudoElement_LeftArrow;
4388 break;
4389
4390 case PE_IndicatorArrowRight:
4391 pseudoElement = PseudoElement_RightArrow;
4392 break;
4393
4394 case PE_IndicatorColumnViewArrow:
4395 if (const QStyleOptionViewItem *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4396 bool reverse = (viewOpt->direction == Qt::RightToLeft);
4397 pseudoElement = reverse ? PseudoElement_LeftArrow : PseudoElement_RightArrow;
4398 } else {
4399 pseudoElement = PseudoElement_RightArrow;
4400 }
4401 break;
4402
4403 case PE_IndicatorBranch:
4404 if (const QStyleOptionViewItemV2 *v2 = qstyleoption_cast<const QStyleOptionViewItemV2 *>(opt)) {
4405 QRenderRule subRule = renderRule(w, opt, PseudoElement_TreeViewBranch);
4406 if (subRule.hasDrawable()) {
4407 if ((v2->state & QStyle::State_Selected) && v2->showDecorationSelected)
4408 p->fillRect(v2->rect, v2->palette.highlight());
4409 else if (v2->features & QStyleOptionViewItemV2::Alternate)
4410 p->fillRect(v2->rect, v2->palette.alternateBase());
4411 subRule.drawRule(p, opt->rect);
4412 } else {
4413 QStyleOptionViewItemV2 v2Copy(*v2);
4414 if (v2->showDecorationSelected) {
4415 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_ViewItem);
4416 if (v2->state & QStyle::State_Selected) {
4417 subRule2.configurePalette(&v2Copy.palette, QPalette::NoRole, QPalette::Highlight);
4418 } else if (v2->features & QStyleOptionViewItemV2::Alternate) {
4419 subRule2.configurePalette(&v2Copy.palette, QPalette::NoRole, QPalette::AlternateBase);
4420 } else if (subRule2.hasBackground()) {
4421 p->fillRect(v2->rect, subRule2.background()->brush);
4422 }
4423 } else if (v2->features & QStyleOptionViewItemV2::Alternate) {
4424 quint64 pc = v2->state & QStyle::State_Enabled ? PseudoClass_Enabled : PseudoClass_Disabled;
4425 pc |= PseudoClass_Alternate;
4426 QRenderRule subRule2 = renderRule(w, PseudoElement_ViewItem, pc);
4427 subRule2.configurePalette(&v2Copy.palette, QPalette::NoRole, QPalette::AlternateBase);
4428 }
4429 baseStyle()->drawPrimitive(pe, &v2Copy, p, w);
4430 }
4431 }
4432 return;
4433
4434 case PE_PanelTipLabel:
4435 if (!rule.hasDrawable())
4436 break;
4437
4438 if (const QStyleOptionFrame *frmOpt = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4439 if (rule.hasNativeBorder()) {
4440 rule.drawBackground(p, opt->rect);
4441 QStyleOptionFrame optCopy(*frmOpt);
4442 optCopy.rect = rule.borderRect(opt->rect);
4443 optCopy.palette.setBrush(QPalette::Window, Qt::NoBrush); // oh dear
4444 baseStyle()->drawPrimitive(pe, &optCopy, p, w);
4445 } else {
4446 rule.drawRule(p, opt->rect);
4447 }
4448 }
4449 return;
4450
4451 case PE_FrameGroupBox:
4452 if (rule.hasNativeBorder())
4453 break;
4454 rule.drawBorder(p, opt->rect);
4455 return;
4456
4457#ifndef QT_NO_TABWIDGET
4458 case PE_FrameTabWidget:
4459 if (const QStyleOptionTabWidgetFrame *frm = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4460 QRenderRule subRule = renderRule(w, opt, PseudoElement_TabWidgetPane);
4461 if (subRule.hasNativeBorder()) {
4462 subRule.drawBackground(p, opt->rect);
4463 QStyleOptionTabWidgetFrame frmCopy(*frm);
4464 subRule.configurePalette(&frmCopy.palette, QPalette::WindowText, QPalette::Window);
4465 baseStyle()->drawPrimitive(pe, &frmCopy, p, w);
4466 } else {
4467 subRule.drawRule(p, opt->rect);
4468 }
4469 return;
4470 }
4471 break;
4472#endif // QT_NO_TABWIDGET
4473
4474 case PE_IndicatorProgressChunk:
4475 pseudoElement = PseudoElement_ProgressBarChunk;
4476 break;
4477
4478 case PE_IndicatorTabTear:
4479 pseudoElement = PseudoElement_TabBarTear;
4480 break;
4481
4482 case PE_FrameFocusRect:
4483 if (!rule.hasNativeOutline()) {
4484 rule.drawOutline(p, opt->rect);
4485 return;
4486 }
4487 break;
4488
4489 case PE_IndicatorDockWidgetResizeHandle:
4490 pseudoElement = PseudoElement_DockWidgetSeparator;
4491 break;
4492
4493 case PE_PanelItemViewItem:
4494 if (!styleHint(SH_ItemView_ShowDecorationSelected, opt, w)) {
4495 rect = subElementRect(QStyle::SE_ItemViewItemText, opt, w)
4496 | subElementRect(QStyle::SE_ItemViewItemDecoration, opt, w)
4497 | subElementRect(QStyle::SE_ItemViewItemCheckIndicator, opt, w);
4498 }
4499 pseudoElement = PseudoElement_ViewItem;
4500 break;
4501
4502 case PE_PanelItemViewRow:
4503 ParentStyle::drawPrimitive(pe, opt, p, w);
4504 if (!styleHint(SH_ItemView_ShowDecorationSelected, opt, w))
4505 return;
4506 pseudoElement = PseudoElement_ViewItem;
4507 break;
4508
4509 case PE_PanelScrollAreaCorner:
4510 pseudoElement = PseudoElement_ScrollAreaCorner;
4511 break;
4512
4513 default:
4514 break;
4515 }
4516
4517 if (pseudoElement != PseudoElement_None) {
4518 QRenderRule subRule = renderRule(w, opt, pseudoElement);
4519 if (subRule.hasDrawable()) {
4520 subRule.drawRule(p, rect);
4521 } else {
4522 baseStyle()->drawPrimitive(pe, opt, p, w);
4523 }
4524 } else {
4525 baseStyle()->drawPrimitive(pe, opt, p, w);
4526 }
4527}
4528
4529QPixmap QStyleSheetStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap& pixmap,
4530 const QStyleOption *option) const
4531{
4532 return baseStyle()->generatedIconPixmap(iconMode, pixmap, option);
4533}
4534
4535QStyle::SubControl QStyleSheetStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
4536 const QPoint &pt, const QWidget *w) const
4537{
4538 RECURSION_GUARD(return baseStyle()->hitTestComplexControl(cc, opt, pt, w))
4539 switch (cc) {
4540 case CC_TitleBar:
4541 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
4542 QRenderRule rule = renderRule(w, opt, PseudoElement_TitleBar);
4543 if (rule.hasDrawable() || rule.hasBox() || rule.hasBorder()) {
4544 QHash<QStyle::SubControl, QRect> layout = titleBarLayout(w, tb);
4545 QRect r;
4546 QStyle::SubControl sc = QStyle::SC_None;
4547 uint ctrl = SC_TitleBarSysMenu;
4548 while (ctrl <= SC_TitleBarLabel) {
4549 r = layout[QStyle::SubControl(ctrl)];
4550 if (r.isValid() && r.contains(pt)) {
4551 sc = QStyle::SubControl(ctrl);
4552 break;
4553 }
4554 ctrl <<= 1;
4555 }
4556 return sc;
4557 }
4558 }
4559 break;
4560
4561 case CC_MdiControls:
4562 if (hasStyleRule(w, PseudoElement_MdiCloseButton)
4563 || hasStyleRule(w, PseudoElement_MdiNormalButton)
4564 || hasStyleRule(w, PseudoElement_MdiMinButton))
4565 return QWindowsStyle::hitTestComplexControl(cc, opt, pt, w);
4566 break;
4567
4568 case CC_ScrollBar: {
4569 QRenderRule rule = renderRule(w, opt);
4570 if (!rule.hasDrawable() && !rule.hasBox())
4571 break;
4572 }
4573 // intentionally falls through
4574 case CC_SpinBox:
4575 case CC_GroupBox:
4576 case CC_ComboBox:
4577 case CC_Slider:
4578 case CC_ToolButton:
4579 return QWindowsStyle::hitTestComplexControl(cc, opt, pt, w);
4580 default:
4581 break;
4582 }
4583
4584 return baseStyle()->hitTestComplexControl(cc, opt, pt, w);
4585}
4586
4587QRect QStyleSheetStyle::itemPixmapRect(const QRect &rect, int alignment, const QPixmap &pixmap) const
4588{
4589 return baseStyle()->itemPixmapRect(rect, alignment, pixmap);
4590}
4591
4592QRect QStyleSheetStyle::itemTextRect(const QFontMetrics &metrics, const QRect& rect, int alignment,
4593 bool enabled, const QString& text) const
4594{
4595 return baseStyle()->itemTextRect(metrics, rect, alignment, enabled, text);
4596}
4597
4598int QStyleSheetStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWidget *w) const
4599{
4600 RECURSION_GUARD(return baseStyle()->pixelMetric(m, opt, w))
4601
4602 QRenderRule rule = renderRule(w, opt);
4603 QRenderRule subRule;
4604
4605 switch (m) {
4606 case PM_MenuButtonIndicator:
4607#ifndef QT_NO_TOOLBUTTON
4608 // QToolButton adds this directly to the width
4609 if (qobject_cast<const QToolButton *>(w) && (rule.hasBox() || !rule.hasNativeBorder()))
4610 return 0;
4611#endif
4612 subRule = renderRule(w, opt, PseudoElement_PushButtonMenuIndicator);
4613 if (subRule.hasContentsSize())
4614 return subRule.size().width();
4615 break;
4616
4617 case PM_ButtonShiftHorizontal:
4618 case PM_ButtonShiftVertical:
4619 case PM_ButtonMargin:
4620 case PM_ButtonDefaultIndicator:
4621 if (rule.hasBox())
4622 return 0;
4623 break;
4624
4625 case PM_DefaultFrameWidth:
4626 if (!rule.hasNativeBorder())
4627 return rule.border()->borders[LeftEdge];
4628 break;
4629
4630 case PM_ExclusiveIndicatorWidth:
4631 case PM_IndicatorWidth:
4632 case PM_ExclusiveIndicatorHeight:
4633 case PM_IndicatorHeight:
4634 subRule = renderRule(w, opt, PseudoElement_Indicator);
4635 if (subRule.hasContentsSize()) {
4636 return (m == PM_ExclusiveIndicatorWidth) || (m == PM_IndicatorWidth)
4637 ? subRule.size().width() : subRule.size().height();
4638 }
4639 break;
4640
4641 case PM_DockWidgetFrameWidth:
4642 case PM_ToolTipLabelFrameWidth: // border + margin + padding (support only one width)
4643 if (!rule.hasDrawable())
4644 break;
4645
4646 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
4647 + (rule.hasBox() ? rule.box()->margins[LeftEdge] + rule.box()->paddings[LeftEdge]: 0);
4648
4649 case PM_ToolBarFrameWidth:
4650 if (rule.hasBorder() || rule.hasBox())
4651 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
4652 + (rule.hasBox() ? rule.box()->paddings[LeftEdge]: 0);
4653 break;
4654
4655 case PM_MenuPanelWidth:
4656 case PM_MenuBarPanelWidth:
4657 if (rule.hasBorder() || rule.hasBox())
4658 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
4659 + (rule.hasBox() ? rule.box()->margins[LeftEdge]: 0);
4660 break;
4661
4662
4663 case PM_MenuHMargin:
4664 case PM_MenuBarHMargin:
4665 if (rule.hasBox())
4666 return rule.box()->paddings[LeftEdge];
4667 break;
4668
4669 case PM_MenuVMargin:
4670 case PM_MenuBarVMargin:
4671 if (rule.hasBox())
4672 return rule.box()->paddings[TopEdge];
4673 break;
4674
4675 case PM_DockWidgetTitleBarButtonMargin:
4676 case PM_ToolBarItemMargin:
4677 if (rule.hasBox())
4678 return rule.box()->margins[TopEdge];
4679 break;
4680
4681 case PM_ToolBarItemSpacing:
4682 case PM_MenuBarItemSpacing:
4683 if (rule.hasBox() && rule.box()->spacing != -1)
4684 return rule.box()->spacing;
4685 break;
4686
4687 case PM_MenuTearoffHeight:
4688 case PM_MenuScrollerHeight: {
4689 PseudoElement ps = m == PM_MenuTearoffHeight ? PseudoElement_MenuTearoff : PseudoElement_MenuScroller;
4690 subRule = renderRule(w, opt, ps);
4691 if (subRule.hasContentsSize())
4692 return subRule.size().height();
4693 break;
4694 }
4695
4696 case PM_ToolBarExtensionExtent:
4697 break;
4698
4699 case PM_SplitterWidth:
4700 case PM_ToolBarSeparatorExtent:
4701 case PM_ToolBarHandleExtent: {
4702 PseudoElement ps;
4703 if (m == PM_ToolBarHandleExtent) ps = PseudoElement_ToolBarHandle;
4704 else if (m == PM_SplitterWidth) ps = PseudoElement_SplitterHandle;
4705 else ps = PseudoElement_ToolBarSeparator;
4706 subRule = renderRule(w, opt, ps);
4707 if (subRule.hasContentsSize()) {
4708 QSize sz = subRule.size();
4709 return (opt && opt->state & QStyle::State_Horizontal) ? sz.width() : sz.height();
4710 }
4711 break;
4712 }
4713
4714 case PM_RadioButtonLabelSpacing:
4715 if (rule.hasBox() && rule.box()->spacing != -1)
4716 return rule.box()->spacing;
4717 break;
4718 case PM_CheckBoxLabelSpacing:
4719 if (qobject_cast<const QCheckBox *>(w)) {
4720 if (rule.hasBox() && rule.box()->spacing != -1)
4721 return rule.box()->spacing;
4722 }
4723 // assume group box
4724 subRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
4725 if (subRule.hasBox() && subRule.box()->spacing != -1)
4726 return subRule.box()->spacing;
4727 break;
4728
4729#ifndef QT_NO_SCROLLBAR
4730 case PM_ScrollBarExtent:
4731 if (rule.hasContentsSize()) {
4732 QSize sz = rule.size();
4733 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt))
4734 return sb->orientation == Qt::Horizontal ? sz.height() : sz.width();
4735 return sz.width() == -1 ? sz.height() : sz.width();
4736 }
4737 break;
4738
4739 case PM_ScrollBarSliderMin:
4740 if (hasStyleRule(w, PseudoElement_ScrollBarSlider)) {
4741 subRule = renderRule(w, opt, PseudoElement_ScrollBarSlider);
4742 QSize msz = subRule.minimumSize();
4743 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt))
4744 return sb->orientation == Qt::Horizontal ? msz.width() : msz.height();
4745 return msz.width() == -1 ? msz.height() : msz.width();
4746 }
4747 break;
4748#endif // QT_NO_SCROLLBAR
4749
4750 case PM_ProgressBarChunkWidth:
4751 subRule = renderRule(w, opt, PseudoElement_ProgressBarChunk);
4752 if (subRule.hasContentsSize()) {
4753 QSize sz = subRule.size();
4754 return (opt->state & QStyle::State_Horizontal)
4755 ? sz.width() : sz.height();
4756 }
4757 break;
4758
4759 case PM_TabBarTabHSpace:
4760 case PM_TabBarTabVSpace:
4761 subRule = renderRule(w, opt, PseudoElement_TabBarTab);
4762 if (subRule.hasBox() || subRule.hasBorder())
4763 return 0;
4764 break;
4765
4766 case PM_TabBarScrollButtonWidth: {
4767 subRule = renderRule(w, opt, PseudoElement_TabBarScroller);
4768 if (subRule.hasContentsSize()) {
4769 QSize sz = subRule.size();
4770 return sz.width() != -1 ? sz.width() : sz.height();
4771 }
4772 }
4773 break;
4774
4775 case PM_TabBarTabShiftHorizontal:
4776 case PM_TabBarTabShiftVertical:
4777 subRule = renderRule(w, opt, PseudoElement_TabBarTab);
4778 if (subRule.hasBox())
4779 return 0;
4780 break;
4781
4782 case PM_TabBarBaseOverlap:
4783 if (hasStyleRule(w->parentWidget(), PseudoElement_TabWidgetPane)) {
4784 return 0;
4785 }
4786 break;
4787
4788 case PM_SliderThickness: // horizontal slider's height (sizeHint)
4789 case PM_SliderLength: // minimum length of slider
4790 if (rule.hasContentsSize()) {
4791 bool horizontal = opt->state & QStyle::State_Horizontal;
4792 if (m == PM_SliderThickness) {
4793 QSize sz = rule.size();
4794 return horizontal ? sz.height() : sz.width();
4795 } else {
4796 QSize msz = rule.minimumContentsSize();
4797 return horizontal ? msz.width() : msz.height();
4798 }
4799 }
4800 break;
4801
4802 case PM_SliderControlThickness: {
4803 QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderHandle);
4804 if (!subRule.hasContentsSize())
4805 break;
4806 QSize size = subRule.size();
4807 return (opt->state & QStyle::State_Horizontal) ? size.height() : size.width();
4808 }
4809
4810 case PM_ToolBarIconSize:
4811 case PM_ListViewIconSize:
4812 case PM_IconViewIconSize:
4813 case PM_TabBarIconSize:
4814 case PM_MessageBoxIconSize:
4815 case PM_ButtonIconSize:
4816 case PM_SmallIconSize:
4817 if (rule.hasStyleHint(QLatin1String("icon-size"))) {
4818 return rule.styleHint(QLatin1String("icon-size")).toSize().width();
4819 }
4820 break;
4821
4822 case PM_DockWidgetTitleMargin: {
4823 QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetTitle);
4824 if (!subRule.hasBox())
4825 break;
4826 return (subRule.border() ? subRule.border()->borders[TopEdge] : 0)
4827 + (subRule.hasBox() ? subRule.box()->margins[TopEdge] + subRule.box()->paddings[TopEdge]: 0);
4828 }
4829
4830 case PM_DockWidgetSeparatorExtent: {
4831 QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetSeparator);
4832 if (!subRule.hasContentsSize())
4833 break;
4834 QSize sz = subRule.size();
4835 return qMax(sz.width(), sz.height());
4836 }
4837
4838 case PM_TitleBarHeight: {
4839 QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
4840 if (subRule.hasContentsSize())
4841 return subRule.size().height();
4842 else if (subRule.hasBox() || subRule.hasBorder()) {
4843 QFontMetrics fm = opt ? opt->fontMetrics : w->fontMetrics();
4844 return subRule.size(QSize(0, fm.lineSpacing())).height();
4845 }
4846 break;
4847 }
4848
4849 case PM_MdiSubWindowFrameWidth:
4850 if (rule.hasBox() || rule.hasBorder()) {
4851 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
4852 + (rule.hasBox() ? rule.box()->paddings[LeftEdge]+rule.box()->margins[LeftEdge]: 0);
4853 }
4854 break;
4855
4856 case PM_MdiSubWindowMinimizedWidth: {
4857 QRenderRule subRule = renderRule(w, PseudoElement_None, PseudoClass_Minimized);
4858 int width = subRule.size().width();
4859 if (width != -1)
4860 return width;
4861 break;
4862 }
4863 default:
4864 break;
4865 }
4866
4867 return baseStyle()->pixelMetric(m, opt, w);
4868}
4869
4870QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
4871 const QSize &csz, const QWidget *w) const
4872{
4873 RECURSION_GUARD(return baseStyle()->sizeFromContents(ct, opt, csz, w))
4874
4875 QRenderRule rule = renderRule(w, opt);
4876 QSize sz = rule.adjustSize(csz);
4877
4878 switch (ct) {
4879 case CT_SpinBox: // ### hopelessly broken QAbstractSpinBox (part 1)
4880 if (rule.hasBox() || !rule.hasNativeBorder())
4881 return csz;
4882 return rule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, sz, w)
4883 : QWindowsStyle::sizeFromContents(ct, opt, sz, w);
4884 case CT_ToolButton:
4885 if (rule.hasBox() || !rule.hasNativeBorder() || !rule.baseStyleCanDraw())
4886 sz += QSize(3, 3); // ### broken QToolButton
4887 //fall thought
4888 case CT_ComboBox:
4889 case CT_PushButton:
4890 if (rule.hasBox() || !rule.hasNativeBorder()) {
4891 if(ct == CT_ComboBox) {
4892 //add some space for the drop down.
4893 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
4894 QRect comboRect = positionRect(w, rule, subRule, PseudoElement_ComboBoxDropDown, opt->rect, opt->direction);
4895 //+2 because there is hardcoded margins in QCommonStyle::drawControl(CE_ComboBoxLabel)
4896 sz += QSize(comboRect.width() + 2, 0);
4897 }
4898 return rule.boxSize(sz);
4899 }
4900 sz = rule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, sz, w)
4901 : QWindowsStyle::sizeFromContents(ct, opt, sz, w);
4902 return rule.boxSize(sz, Margin);
4903
4904 case CT_HeaderSection: {
4905 if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4906 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
4907 if (subRule.hasGeometry() || subRule.hasBox() || !subRule.hasNativeBorder()) {
4908 sz = subRule.adjustSize(csz);
4909 if (!subRule.hasGeometry()) {
4910 QSize nativeContentsSize;
4911 bool nullIcon = hdr->icon.isNull();
4912 int iconSize = nullIcon ? 0 : pixelMetric(QStyle::PM_SmallIconSize, hdr, w);
4913 QSize txt = hdr->fontMetrics.size(0, hdr->text);
4914 nativeContentsSize.setHeight(qMax(iconSize, txt.height()));
4915 nativeContentsSize.setWidth(iconSize + txt.width());
4916 sz = sz.expandedTo(nativeContentsSize);
4917 }
4918 return subRule.size(sz);
4919 }
4920 return subRule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, sz, w)
4921 : QWindowsStyle::sizeFromContents(ct, opt, sz, w);
4922 }
4923 }
4924 break;
4925 case CT_GroupBox:
4926 case CT_LineEdit:
4927#ifndef QT_NO_SPINBOX
4928 // ### hopelessly broken QAbstractSpinBox (part 2)
4929 if (QAbstractSpinBox *spinBox = qobject_cast<QAbstractSpinBox *>(w->parentWidget())) {
4930 QRenderRule rule = renderRule(spinBox, opt);
4931 if (rule.hasBox() || !rule.hasNativeBorder())
4932 return csz;
4933 return rule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, sz, w)
4934 : QWindowsStyle::sizeFromContents(ct, opt, sz, w);
4935 }
4936#endif
4937 if (rule.hasBox() || !rule.hasNativeBorder()) {
4938 return rule.boxSize(sz);
4939 }
4940 break;
4941
4942 case CT_CheckBox:
4943 case CT_RadioButton:
4944 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4945 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
4946 bool isRadio = (ct == CT_RadioButton);
4947 int iw = pixelMetric(isRadio ? PM_ExclusiveIndicatorWidth
4948 : PM_IndicatorWidth, btn, w);
4949 int ih = pixelMetric(isRadio ? PM_ExclusiveIndicatorHeight
4950 : PM_IndicatorHeight, btn, w);
4951
4952 int spacing = pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
4953 : PM_CheckBoxLabelSpacing, btn, w);
4954 sz.setWidth(sz.width() + iw + spacing);
4955 sz.setHeight(qMax(sz.height(), ih));
4956 return rule.boxSize(sz);
4957 }
4958 }
4959 break;
4960
4961 case CT_Menu:
4962 case CT_MenuBar: // already has everything!
4963 case CT_ScrollBar:
4964 if (rule.hasBox() || rule.hasBorder())
4965 return sz;
4966 break;
4967
4968 case CT_MenuItem:
4969 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4970 PseudoElement pe = (mi->menuItemType == QStyleOptionMenuItem::Separator)
4971 ? PseudoElement_MenuSeparator : PseudoElement_Item;
4972 QRenderRule subRule = renderRule(w, opt, pe);
4973 if ((pe == PseudoElement_MenuSeparator) && subRule.hasContentsSize()) {
4974 return QSize(sz.width(), subRule.size().height());
4975 } else if ((pe == PseudoElement_Item) && (subRule.hasBox() || subRule.hasBorder())) {
4976 int width = csz.width(), height = qMax(csz.height(), mi->fontMetrics.height());
4977 if (!mi->icon.isNull()) {
4978 int iconExtent = pixelMetric(PM_SmallIconSize);
4979 height = qMax(height, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height());
4980 }
4981 width += mi->tabWidth;
4982 return subRule.boxSize(csz.expandedTo(subRule.minimumContentsSize()));
4983 }
4984 }
4985 break;
4986
4987 case CT_Splitter:
4988 case CT_MenuBarItem: {
4989 PseudoElement pe = (ct == CT_Splitter) ? PseudoElement_SplitterHandle : PseudoElement_Item;
4990 QRenderRule subRule = renderRule(w, opt, pe);
4991 if (subRule.hasBox() || subRule.hasBorder())
4992 return subRule.boxSize(sz);
4993 break;
4994 }
4995
4996 case CT_ProgressBar:
4997 case CT_SizeGrip:
4998 return (rule.hasContentsSize())
4999 ? rule.size(sz)
5000 : rule.boxSize(baseStyle()->sizeFromContents(ct, opt, sz, w));
5001 break;
5002
5003 case CT_Slider:
5004 if (rule.hasBorder() || rule.hasBox() || rule.hasGeometry())
5005 return rule.boxSize(sz);
5006 break;
5007
5008#ifndef QT_NO_TABBAR
5009 case CT_TabBarTab: {
5010 QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTab);
5011 if (subRule.hasBox() || !subRule.hasNativeBorder()) {
5012 int spaceForIcon = 0;
5013 bool vertical = false;
5014 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
5015 if (!tab->icon.isNull())
5016 spaceForIcon = 6 /* icon offset */ + 4 /* spacing */ + 2 /* magic */; // ###: hardcoded to match with common style
5017 vertical = verticalTabs(tab->shape);
5018 }
5019 sz = csz + QSize(vertical ? 0 : spaceForIcon, vertical ? spaceForIcon : 0);
5020 return subRule.boxSize(subRule.adjustSize(sz));
5021 }
5022#ifdef Q_WS_MAC
5023 if (baseStyle()->inherits("QMacStyle")) {
5024 //adjust the size after the call to the style because the mac style ignore the size arguments anyway.
5025 //this might cause the (max-){width,height} property to include the native style border while they should not.
5026 return subRule.adjustSize(baseStyle()->sizeFromContents(ct, opt, csz, w));
5027 }
5028#endif
5029 sz = subRule.adjustSize(csz);
5030 break;
5031 }
5032#endif // QT_NO_TABBAR
5033
5034 case CT_MdiControls:
5035 if (const QStyleOptionComplex *ccOpt = qstyleoption_cast<const QStyleOptionComplex *>(opt)) {
5036 if (!hasStyleRule(w, PseudoElement_MdiCloseButton)
5037 && !hasStyleRule(w, PseudoElement_MdiNormalButton)
5038 && !hasStyleRule(w, PseudoElement_MdiMinButton))
5039 break;
5040
5041 QList<QVariant> layout = rule.styleHint(QLatin1String("button-layout")).toList();
5042 if (layout.isEmpty())
5043 layout = subControlLayout(QLatin1String("mNX"));
5044
5045 int width = 0, height = 0;
5046 for (int i = 0; i < layout.count(); i++) {
5047 int layoutButton = layout[i].toInt();
5048 if (layoutButton < PseudoElement_MdiCloseButton
5049 || layoutButton > PseudoElement_MdiNormalButton)
5050 continue;
5051 QStyle::SubControl sc = knownPseudoElements[layoutButton].subControl;
5052 if (!(ccOpt->subControls & sc))
5053 continue;
5054 QRenderRule subRule = renderRule(w, opt, layoutButton);
5055 QSize sz = subRule.size();
5056 width += sz.width();
5057 height = qMax(height, sz.height());
5058 }
5059
5060 return QSize(width, height);
5061 }
5062 break;
5063
5064#ifndef QT_NO_ITEMVIEWS
5065 case CT_ItemViewItem: {
5066 QRenderRule subRule = renderRule(w, opt, PseudoElement_ViewItem);
5067 sz = baseStyle()->sizeFromContents(ct, opt, csz, w);
5068 sz = subRule.adjustSize(sz);
5069 if (subRule.hasBox() || subRule.hasBorder())
5070 sz = subRule.boxSize(sz);
5071 return sz;
5072 }
5073#endif // QT_NO_ITEMVIEWS
5074
5075 default:
5076 break;
5077 }
5078
5079 return baseStyle()->sizeFromContents(ct, opt, sz, w);
5080}
5081
5082/*!
5083 \internal
5084*/
5085static QLatin1String propertyNameForStandardPixmap(QStyle::StandardPixmap sp)
5086{
5087 switch (sp) {
5088 case QStyle::SP_TitleBarMenuButton: return QLatin1String("titlebar-menu-icon");
5089 case QStyle::SP_TitleBarMinButton: return QLatin1String("titlebar-minimize-icon");
5090 case QStyle::SP_TitleBarMaxButton: return QLatin1String("titlebar-maximize-icon");
5091 case QStyle::SP_TitleBarCloseButton: return QLatin1String("titlebar-close-icon");
5092 case QStyle::SP_TitleBarNormalButton: return QLatin1String("titlebar-normal-icon");
5093 case QStyle::SP_TitleBarShadeButton: return QLatin1String("titlebar-shade-icon");
5094 case QStyle::SP_TitleBarUnshadeButton: return QLatin1String("titlebar-unshade-icon");
5095 case QStyle::SP_TitleBarContextHelpButton: return QLatin1String("titlebar-contexthelp-icon");
5096 case QStyle::SP_DockWidgetCloseButton: return QLatin1String("dockwidget-close-icon");
5097 case QStyle::SP_MessageBoxInformation: return QLatin1String("messagebox-information-icon");
5098 case QStyle::SP_MessageBoxWarning: return QLatin1String("messagebox-warning-icon");
5099 case QStyle::SP_MessageBoxCritical: return QLatin1String("messagebox-critical-icon");
5100 case QStyle::SP_MessageBoxQuestion: return QLatin1String("messagebox-question-icon");
5101 case QStyle::SP_DesktopIcon: return QLatin1String("desktop-icon");
5102 case QStyle::SP_TrashIcon: return QLatin1String("trash-icon");
5103 case QStyle::SP_ComputerIcon: return QLatin1String("computer-icon");
5104 case QStyle::SP_DriveFDIcon: return QLatin1String("floppy-icon");
5105 case QStyle::SP_DriveHDIcon: return QLatin1String("harddisk-icon");
5106 case QStyle::SP_DriveCDIcon: return QLatin1String("cd-icon");
5107 case QStyle::SP_DriveDVDIcon: return QLatin1String("dvd-icon");
5108 case QStyle::SP_DriveNetIcon: return QLatin1String("network-icon");
5109 case QStyle::SP_DirOpenIcon: return QLatin1String("directory-open-icon");
5110 case QStyle::SP_DirClosedIcon: return QLatin1String("directory-closed-icon");
5111 case QStyle::SP_DirLinkIcon: return QLatin1String("directory-link-icon");
5112 case QStyle::SP_FileIcon: return QLatin1String("file-icon");
5113 case QStyle::SP_FileLinkIcon: return QLatin1String("file-link-icon");
5114 case QStyle::SP_FileDialogStart: return QLatin1String("filedialog-start-icon");
5115 case QStyle::SP_FileDialogEnd: return QLatin1String("filedialog-end-icon");
5116 case QStyle::SP_FileDialogToParent: return QLatin1String("filedialog-parent-directory-icon");
5117 case QStyle::SP_FileDialogNewFolder: return QLatin1String("filedialog-new-directory-icon");
5118 case QStyle::SP_FileDialogDetailedView: return QLatin1String("filedialog-detailedview-icon");
5119 case QStyle::SP_FileDialogInfoView: return QLatin1String("filedialog-infoview-icon");
5120 case QStyle::SP_FileDialogContentsView: return QLatin1String("filedialog-contentsview-icon");
5121 case QStyle::SP_FileDialogListView: return QLatin1String("filedialog-listview-icon");
5122 case QStyle::SP_FileDialogBack: return QLatin1String("filedialog-backward-icon");
5123 case QStyle::SP_DirIcon: return QLatin1String("directory-icon");
5124 case QStyle::SP_DialogOkButton: return QLatin1String("dialog-ok-icon");
5125 case QStyle::SP_DialogCancelButton: return QLatin1String("dialog-cancel-icon");
5126 case QStyle::SP_DialogHelpButton: return QLatin1String("dialog-help-icon");
5127 case QStyle::SP_DialogOpenButton: return QLatin1String("dialog-open-icon");
5128 case QStyle::SP_DialogSaveButton: return QLatin1String("dialog-save-icon");
5129 case QStyle::SP_DialogCloseButton: return QLatin1String("dialog-close-icon");
5130 case QStyle::SP_DialogApplyButton: return QLatin1String("dialog-apply-icon");
5131 case QStyle::SP_DialogResetButton: return QLatin1String("dialog-reset-icon");
5132 case QStyle::SP_DialogDiscardButton: return QLatin1String("discard-icon");
5133 case QStyle::SP_DialogYesButton: return QLatin1String("dialog-yes-icon");
5134 case QStyle::SP_DialogNoButton: return QLatin1String("dialog-no-icon");
5135 case QStyle::SP_ArrowUp: return QLatin1String("uparrow-icon");
5136 case QStyle::SP_ArrowDown: return QLatin1String("downarrow-icon");
5137 case QStyle::SP_ArrowLeft: return QLatin1String("leftarrow-icon");
5138 case QStyle::SP_ArrowRight: return QLatin1String("rightarrow-icon");
5139 case QStyle::SP_ArrowBack: return QLatin1String("backward-icon");
5140 case QStyle::SP_ArrowForward: return QLatin1String("forward-icon");
5141 case QStyle::SP_DirHomeIcon: return QLatin1String("home-icon");
5142 default: return QLatin1String("");
5143 }
5144}
5145
5146QIcon QStyleSheetStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *opt,
5147 const QWidget *w) const
5148{
5149 RECURSION_GUARD(return baseStyle()->standardIcon(standardIcon, opt, w))
5150 QString s = propertyNameForStandardPixmap(standardIcon);
5151 if (!s.isEmpty()) {
5152 QRenderRule rule = renderRule(w, opt);
5153 if (rule.hasStyleHint(s))
5154 return qVariantValue<QIcon>(rule.styleHint(s));
5155 }
5156 return baseStyle()->standardIcon(standardIcon, opt, w);
5157}
5158
5159QPalette QStyleSheetStyle::standardPalette() const
5160{
5161 return baseStyle()->standardPalette();
5162}
5163
5164QPixmap QStyleSheetStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
5165 const QWidget *w) const
5166{
5167 RECURSION_GUARD(return baseStyle()->standardPixmap(standardPixmap, opt, w))
5168 QString s = propertyNameForStandardPixmap(standardPixmap);
5169 if (!s.isEmpty()) {
5170 QRenderRule rule = renderRule(w, opt);
5171 if (rule.hasStyleHint(s)) {
5172 QIcon icon = qVariantValue<QIcon>(rule.styleHint(s));
5173 return icon.pixmap(16, 16); // ###: unhard-code this if someone complains
5174 }
5175 }
5176 return baseStyle()->standardPixmap(standardPixmap, opt, w);
5177}
5178
5179int QStyleSheetStyle::layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2,
5180 Qt::Orientation orientation, const QStyleOption *option,
5181 const QWidget *widget) const
5182{
5183 return baseStyle()->layoutSpacing(control1, control2, orientation, option, widget);
5184}
5185
5186int QStyleSheetStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1 ,
5187 QSizePolicy::ControlType control2,
5188 Qt::Orientation orientation,
5189 const QStyleOption * option ,
5190 const QWidget * widget) const
5191{
5192 return baseStyle()->layoutSpacing(control1, control2, orientation, option, widget);
5193}
5194
5195int QStyleSheetStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
5196 QStyleHintReturn *shret) const
5197{
5198 RECURSION_GUARD(return baseStyle()->styleHint(sh, opt, w, shret))
5199 // Prevent endless loop if somebody use isActiveWindow property as selector.
5200 // QWidget::isActiveWindow uses this styleHint to determine if the window is active or not
5201 if (sh == SH_Widget_ShareActivation)
5202 return baseStyle()->styleHint(sh, opt, w, shret);
5203
5204 QRenderRule rule = renderRule(w, opt);
5205 QString s;
5206 switch (sh) {
5207 case SH_LineEdit_PasswordCharacter: s = QLatin1String("lineedit-password-character"); break;
5208 case SH_DitherDisabledText: s = QLatin1String("dither-disabled-text"); break;
5209 case SH_EtchDisabledText: s = QLatin1String("etch-disabled-text"); break;
5210 case SH_ItemView_ActivateItemOnSingleClick: s = QLatin1String("activate-on-singleclick"); break;
5211 case SH_ItemView_ShowDecorationSelected: s = QLatin1String("show-decoration-selected"); break;
5212 case SH_Table_GridLineColor: s = QLatin1String("gridline-color"); break;
5213 case SH_DialogButtonLayout: s = QLatin1String("button-layout"); break;
5214 case SH_ToolTipLabel_Opacity: s = QLatin1String("opacity"); break;
5215 case SH_ComboBox_Popup: s = QLatin1String("combobox-popup"); break;
5216 case SH_ComboBox_ListMouseTracking: s = QLatin1String("combobox-list-mousetracking"); break;
5217 case SH_MenuBar_AltKeyNavigation: s = QLatin1String("menubar-altkey-navigation"); break;
5218 case SH_Menu_Scrollable: s = QLatin1String("menu-scrollable"); break;
5219 case SH_DrawMenuBarSeparator: s = QLatin1String("menubar-separator"); break;
5220 case SH_MenuBar_MouseTracking: s = QLatin1String("mouse-tracking"); break;
5221 case SH_SpinBox_ClickAutoRepeatRate: s = QLatin1String("spinbox-click-autorepeat-rate"); break;
5222 case SH_SpinControls_DisableOnBounds: s = QLatin1String("spincontrol-disable-on-bounds"); break;
5223 case SH_MessageBox_TextInteractionFlags: s = QLatin1String("messagebox-text-interaction-flags"); break;
5224 case SH_ToolButton_PopupDelay: s = QLatin1String("toolbutton-popup-delay"); break;
5225 case SH_ToolBox_SelectedPageTitleBold:
5226 if (renderRule(w, opt, PseudoElement_ToolBoxTab).hasFont)
5227 return 0;
5228 break;
5229 case SH_GroupBox_TextLabelColor:
5230 if (rule.hasPalette() && rule.palette()->foreground.style() != Qt::NoBrush)
5231 return rule.palette()->foreground.color().rgba();
5232 break;
5233 case SH_ScrollView_FrameOnlyAroundContents: s = QLatin1String("scrollview-frame-around-contents"); break;
5234 case SH_ScrollBar_ContextMenu: s = QLatin1String("scrollbar-contextmenu"); break;
5235 case SH_ScrollBar_LeftClickAbsolutePosition: s = QLatin1String("scrollbar-leftclick-absolute-position"); break;
5236 case SH_ScrollBar_MiddleClickAbsolutePosition: s = QLatin1String("scrollbar-middleclick-absolute-position"); break;
5237 case SH_ScrollBar_RollBetweenButtons: s = QLatin1String("scrollbar-roll-between-buttons"); break;
5238 case SH_ScrollBar_ScrollWhenPointerLeavesControl: s = QLatin1String("scrollbar-scroll-when-pointer-leaves-control"); break;
5239 case SH_TabBar_Alignment:
5240#ifndef QT_NO_TABWIDGET
5241 if (qobject_cast<const QTabWidget *>(w)) {
5242 rule = renderRule(w, opt, PseudoElement_TabWidgetTabBar);
5243 if (rule.hasPosition())
5244 return rule.position()->position;
5245 }
5246#endif // QT_NO_TABWIDGET
5247 s = QLatin1String("alignment");
5248 break;
5249 case SH_TabBar_ElideMode: s = QLatin1String("tabbar-elide-mode"); break;
5250 case SH_TabBar_PreferNoArrows: s = QLatin1String("tabbar-prefer-no-arrows"); break;
5251 case SH_ComboBox_PopupFrameStyle:
5252#ifndef QT_NO_COMBOBOX
5253 if (qobject_cast<const QComboBox *>(w)) {
5254 QAbstractItemView *view = qFindChild<QAbstractItemView *>(w);
5255 QRenderRule subRule = renderRule(view, PseudoElement_None);
5256 if (subRule.hasBox() || !subRule.hasNativeBorder())
5257 return QFrame::NoFrame;
5258 }
5259#endif // QT_NO_COMBOBOX
5260 break;
5261 case SH_DialogButtonBox_ButtonsHaveIcons: s = QLatin1String("dialogbuttonbox-buttons-have-icons"); break;
5262 case SH_Workspace_FillSpaceOnMaximize: s = QLatin1String("mdi-fill-space-on-maximize"); break;
5263 case SH_TitleBar_NoBorder:
5264 if (rule.hasBorder())
5265 return !rule.border()->borders[LeftEdge];
5266 break;
5267 case SH_TitleBar_AutoRaise: { // plain absurd
5268 QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
5269 if (subRule.hasDrawable())
5270 return 1;
5271 break;
5272 }
5273 case SH_ItemView_ArrowKeysNavigateIntoChildren: s = QLatin1String("arrow-keys-navigate-into-children"); break;
5274 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea: s = QLatin1String("paint-alternating-row-colors-for-empty-area"); break;
5275 default: break;
5276 }
5277 if (!s.isEmpty() && rule.hasStyleHint(s)) {
5278 return rule.styleHint(s).toInt();
5279 }
5280
5281 return baseStyle()->styleHint(sh, opt, w, shret);
5282}
5283
5284QRect QStyleSheetStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
5285 const QWidget *w) const
5286{
5287 RECURSION_GUARD(return baseStyle()->subControlRect(cc, opt, sc, w))
5288
5289 QRenderRule rule = renderRule(w, opt);
5290 switch (cc) {
5291 case CC_ComboBox:
5292 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5293 if (rule.hasBox() || !rule.hasNativeBorder()) {
5294 switch (sc) {
5295 case SC_ComboBoxFrame: return rule.borderRect(opt->rect);
5296 case SC_ComboBoxEditField:
5297 {
5298 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
5299 QRect r = rule.contentsRect(opt->rect);
5300 QRect r2 = positionRect(w, rule, subRule, PseudoElement_ComboBoxDropDown,
5301 opt->rect, opt->direction);
5302 if (subRule.hasPosition() && subRule.position()->position & Qt::AlignLeft) {
5303 return visualRect(opt->direction, r, r.adjusted(r2.width(),0,0,0));
5304 } else {
5305 return visualRect(opt->direction, r, r.adjusted(0,0,-r2.width(),0));
5306 }
5307 }
5308 case SC_ComboBoxArrow: {
5309 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
5310 return positionRect(w, rule, subRule, PseudoElement_ComboBoxDropDown, opt->rect, opt->direction);
5311 }
5312 case SC_ComboBoxListBoxPopup:
5313 default:
5314 return baseStyle()->subControlRect(cc, opt, sc, w);
5315 }
5316 }
5317
5318 QStyleOptionComboBox comboBox(*cb);
5319 comboBox.rect = rule.borderRect(opt->rect);
5320 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &comboBox, sc, w)
5321 : QWindowsStyle::subControlRect(cc, &comboBox, sc, w);
5322 }
5323 break;
5324
5325#ifndef QT_NO_SPINBOX
5326 case CC_SpinBox:
5327 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5328 QRenderRule upRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
5329 QRenderRule downRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
5330 bool ruleMatch = rule.hasBox() || !rule.hasNativeBorder();
5331 bool upRuleMatch = upRule.hasGeometry();
5332 bool downRuleMatch = downRule.hasGeometry();
5333 if (ruleMatch || upRuleMatch || downRuleMatch) {
5334 switch (sc) {
5335 case SC_SpinBoxFrame:
5336 return rule.borderRect(opt->rect);
5337 case SC_SpinBoxEditField:
5338 {
5339 QRect r = rule.contentsRect(opt->rect);
5340 // Use the widest button on each side to determine edit field size.
5341 Qt::Alignment upAlign, downAlign;
5342
5343 upAlign = upRule.hasPosition() ? upRule.position()->position
5344 : Qt::Alignment(Qt::AlignRight);
5345 upAlign = resolveAlignment(opt->direction, upAlign);
5346
5347 downAlign = downRule.hasPosition() ? downRule.position()->position
5348 : Qt::Alignment(Qt::AlignRight);
5349 downAlign = resolveAlignment(opt->direction, downAlign);
5350
5351 int upSize = subControlRect(CC_SpinBox, opt, SC_SpinBoxUp, w).width();
5352 int downSize = subControlRect(CC_SpinBox, opt, SC_SpinBoxDown, w).width();
5353 int widestL = qMax((upAlign & Qt::AlignLeft) ? upSize : 0,
5354 (downAlign & Qt::AlignLeft) ? downSize : 0);
5355 int widestR = qMax((upAlign & Qt::AlignRight) ? upSize : 0,
5356 (downAlign & Qt::AlignRight) ? downSize : 0);
5357 r.setRight(r.right() - widestR);
5358 r.setLeft(r.left() + widestL);
5359 return r;
5360 }
5361 case SC_SpinBoxDown:
5362 if (downRuleMatch)
5363 return positionRect(w, rule, downRule, PseudoElement_SpinBoxDownButton,
5364 opt->rect, opt->direction);
5365 break;
5366 case SC_SpinBoxUp:
5367 if (upRuleMatch)
5368 return positionRect(w, rule, upRule, PseudoElement_SpinBoxUpButton,
5369 opt->rect, opt->direction);
5370 break;
5371 default:
5372 break;
5373 }
5374
5375 return baseStyle()->subControlRect(cc, opt, sc, w);
5376 }
5377
5378 QStyleOptionSpinBox spinBox(*spin);
5379 spinBox.rect = rule.borderRect(opt->rect);
5380 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &spinBox, sc, w)
5381 : QWindowsStyle::subControlRect(cc, &spinBox, sc, w);
5382 }
5383 break;
5384#endif // QT_NO_SPINBOX
5385
5386 case CC_GroupBox:
5387 if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5388 switch (sc) {
5389 case SC_GroupBoxFrame:
5390 case SC_GroupBoxContents: {
5391 if (rule.hasBox() || !rule.hasNativeBorder()) {
5392 return sc == SC_GroupBoxFrame ? rule.borderRect(opt->rect)
5393 : rule.contentsRect(opt->rect);
5394 }
5395 QStyleOptionGroupBox groupBox(*gb);
5396 groupBox.rect = rule.borderRect(opt->rect);
5397 return baseStyle()->subControlRect(cc, &groupBox, sc, w);
5398 }
5399 default:
5400 case SC_GroupBoxLabel:
5401 case SC_GroupBoxCheckBox: {
5402 QRenderRule indRule = renderRule(w, opt, PseudoElement_GroupBoxIndicator);
5403 QRenderRule labelRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
5404 if (!labelRule.hasPosition() && !labelRule.hasGeometry() && !labelRule.hasBox()
5405 && !labelRule.hasBorder() && !indRule.hasContentsSize()) {
5406 QStyleOptionGroupBox groupBox(*gb);
5407 groupBox.rect = rule.borderRect(opt->rect);
5408 return baseStyle()->subControlRect(cc, &groupBox, sc, w);
5409 }
5410 int tw = opt->fontMetrics.width(gb->text);
5411 int th = opt->fontMetrics.height();
5412 int spacing = pixelMetric(QStyle::PM_CheckBoxLabelSpacing, opt, w);
5413 int iw = pixelMetric(QStyle::PM_IndicatorWidth, opt, w);
5414 int ih = pixelMetric(QStyle::PM_IndicatorHeight, opt, w);
5415
5416 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
5417 tw = tw + iw + spacing;
5418 th = qMax(th, ih);
5419 }
5420 if (!labelRule.hasGeometry()) {
5421 labelRule.geo = new QStyleSheetGeometryData(tw, th, tw, th, -1, -1);
5422 } else {
5423 labelRule.geo->width = tw;
5424 labelRule.geo->height = th;
5425 }
5426 if (!labelRule.hasPosition()) {
5427 labelRule.p = new QStyleSheetPositionData(0, 0, 0, 0, defaultOrigin(PseudoElement_GroupBoxTitle),
5428 gb->textAlignment, PositionMode_Static);
5429 }
5430 QRect r = positionRect(w, rule, labelRule, PseudoElement_GroupBoxTitle,
5431 opt->rect, opt->direction);
5432 if (gb->subControls & SC_GroupBoxCheckBox) {
5433 r = labelRule.contentsRect(r);
5434 if (sc == SC_GroupBoxLabel) {
5435 r.setLeft(r.left() + iw + spacing);
5436 r.setTop(r.center().y() - th/2);
5437 } else {
5438 r = QRect(r.left(), r.center().y() - ih/2, iw, ih);
5439 }
5440 return r;
5441 } else {
5442 return labelRule.contentsRect(r);
5443 }
5444 }
5445 } // switch
5446 }
5447 break;
5448
5449 case CC_ToolButton:
5450 if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
5451 if (rule.hasBox() || !rule.hasNativeBorder()) {
5452 switch (sc) {
5453 case SC_ToolButton: return rule.borderRect(opt->rect);
5454 case SC_ToolButtonMenu: {
5455 QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
5456 return positionRect(w, rule, subRule, PseudoElement_ToolButtonMenu, opt->rect, opt->direction);
5457 }
5458 default:
5459 break;
5460 }
5461 }
5462
5463 QStyleOptionToolButton tool(*tb);
5464 tool.rect = rule.borderRect(opt->rect);
5465 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &tool, sc, w)
5466 : QWindowsStyle::subControlRect(cc, &tool, sc, w);
5467 }
5468 break;
5469
5470#ifndef QT_NO_SCROLLBAR
5471 case CC_ScrollBar:
5472 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5473 QStyleOptionSlider styleOptionSlider(*sb);
5474 styleOptionSlider.rect = rule.borderRect(opt->rect);
5475 if (rule.hasDrawable() || rule.hasBox()) {
5476 QRect grooveRect;
5477 if (!rule.hasBox()) {
5478 grooveRect = rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, sb, SC_ScrollBarGroove, w)
5479 : QWindowsStyle::subControlRect(cc, sb, SC_ScrollBarGroove, w);
5480 } else {
5481 grooveRect = rule.contentsRect(opt->rect);
5482 }
5483
5484 PseudoElement pe = PseudoElement_None;
5485
5486 switch (sc) {
5487 case SC_ScrollBarGroove:
5488 return grooveRect;
5489 case SC_ScrollBarAddPage:
5490 case SC_ScrollBarSubPage:
5491 case SC_ScrollBarSlider: {
5492 QRect contentRect = grooveRect;
5493 if (hasStyleRule(w, PseudoElement_ScrollBarSlider)) {
5494 QRenderRule sliderRule = renderRule(w, opt, PseudoElement_ScrollBarSlider);
5495 Origin origin = sliderRule.hasPosition() ? sliderRule.position()->origin : defaultOrigin(PseudoElement_ScrollBarSlider);
5496 contentRect = rule.originRect(opt->rect, origin);
5497 }
5498 int maxlen = (styleOptionSlider.orientation == Qt::Horizontal) ? contentRect.width() : contentRect.height();
5499 int sliderlen;
5500 if (sb->maximum != sb->minimum) {
5501 uint range = sb->maximum - sb->minimum;
5502 sliderlen = (qint64(sb->pageStep) * maxlen) / (range + sb->pageStep);
5503
5504 int slidermin = pixelMetric(PM_ScrollBarSliderMin, sb, w);
5505 if (sliderlen < slidermin || range > INT_MAX / 2)
5506 sliderlen = slidermin;
5507 if (sliderlen > maxlen)
5508 sliderlen = maxlen;
5509 } else {
5510 sliderlen = maxlen;
5511 }
5512
5513 int sliderstart = (styleOptionSlider.orientation == Qt::Horizontal ? contentRect.left() : contentRect.top())
5514 + sliderPositionFromValue(sb->minimum, sb->maximum, sb->sliderPosition,
5515 maxlen - sliderlen, sb->upsideDown);
5516
5517 QRect sr = (sb->orientation == Qt::Horizontal)
5518 ? QRect(sliderstart, contentRect.top(), sliderlen, contentRect.height())
5519 : QRect(contentRect.left(), sliderstart, contentRect.width(), sliderlen);
5520 if (sc == SC_ScrollBarSlider) {
5521 return sr;
5522 } else if (sc == SC_ScrollBarSubPage) {
5523 return QRect(contentRect.topLeft(), sb->orientation == Qt::Horizontal ? sr.bottomLeft() : sr.topRight());
5524 } else { // SC_ScrollBarAddPage
5525 return QRect(sb->orientation == Qt::Horizontal ? sr.topRight() : sr.bottomLeft(), contentRect.bottomRight());
5526 }
5527 break;
5528 }
5529 case SC_ScrollBarAddLine: pe = PseudoElement_ScrollBarAddLine; break;
5530 case SC_ScrollBarSubLine: pe = PseudoElement_ScrollBarSubLine; break;
5531 case SC_ScrollBarFirst: pe = PseudoElement_ScrollBarFirst; break;
5532 case SC_ScrollBarLast: pe = PseudoElement_ScrollBarLast; break;
5533 default: break;
5534 }
5535 if (hasStyleRule(w,pe)) {
5536 QRenderRule subRule = renderRule(w, opt, pe);
5537 if (subRule.hasPosition() || subRule.hasGeometry() || subRule.hasBox()) {
5538 const QStyleSheetPositionData *pos = subRule.position();
5539 QRect originRect = grooveRect;
5540 if (rule.hasBox()) {
5541 Origin origin = (pos && pos->origin != Origin_Unknown) ? pos->origin : defaultOrigin(pe);
5542 originRect = rule.originRect(opt->rect, origin);
5543 }
5544 return positionRect(w, subRule, pe, originRect, styleOptionSlider.direction);
5545 }
5546 }
5547 }
5548 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &styleOptionSlider, sc, w)
5549 : QWindowsStyle::subControlRect(cc, &styleOptionSlider, sc, w);
5550 }
5551 break;
5552#endif // QT_NO_SCROLLBAR
5553
5554#ifndef QT_NO_SLIDER
5555 case CC_Slider:
5556 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5557 QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderGroove);
5558 if (!subRule.hasDrawable())
5559 break;
5560 subRule.img = 0;
5561 QRect gr = positionRect(w, rule, subRule, PseudoElement_SliderGroove, opt->rect, opt->direction);
5562 switch (sc) {
5563 case SC_SliderGroove:
5564 return gr;
5565 case SC_SliderHandle: {
5566 bool horizontal = slider->orientation & Qt::Horizontal;
5567 QRect cr = subRule.contentsRect(gr);
5568 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SliderHandle);
5569 int len = horizontal ? subRule2.size().width() : subRule2.size().height();
5570 subRule2.img = 0;
5571 subRule2.geo = 0;
5572 cr = positionRect(w, subRule2, PseudoElement_SliderHandle, cr, opt->direction);
5573 int thickness = horizontal ? cr.height() : cr.width();
5574 int sliderPos = sliderPositionFromValue(slider->minimum, slider->maximum, slider->sliderPosition,
5575 (horizontal ? cr.width() : cr.height()) - len, slider->upsideDown);
5576 cr = horizontal ? QRect(cr.x() + sliderPos, cr.y(), len, thickness)
5577 : QRect(cr.x(), cr.y() + sliderPos, thickness, len);
5578 return subRule2.borderRect(cr);
5579 break; }
5580 case SC_SliderTickmarks:
5581 // TODO...
5582 default:
5583 break;
5584 }
5585 }
5586 break;
5587#endif // QT_NO_SLIDER
5588
5589 case CC_MdiControls:
5590 if (hasStyleRule(w, PseudoElement_MdiCloseButton)
5591 || hasStyleRule(w, PseudoElement_MdiNormalButton)
5592 || hasStyleRule(w, PseudoElement_MdiMinButton)) {
5593 QList<QVariant> layout = rule.styleHint(QLatin1String("button-layout")).toList();
5594 if (layout.isEmpty())
5595 layout = subControlLayout(QLatin1String("mNX"));
5596
5597 int x = 0, width = 0;
5598 QRenderRule subRule;
5599 for (int i = 0; i < layout.count(); i++) {
5600 int layoutButton = layout[i].toInt();
5601 if (layoutButton < PseudoElement_MdiCloseButton
5602 || layoutButton > PseudoElement_MdiNormalButton)
5603 continue;
5604 QStyle::SubControl control = knownPseudoElements[layoutButton].subControl;
5605 if (!(opt->subControls & control))
5606 continue;
5607 subRule = renderRule(w, opt, layoutButton);
5608 width = subRule.size().width();
5609 if (sc == control)
5610 break;
5611 x += width;
5612 }
5613
5614 return subRule.borderRect(QRect(x, opt->rect.top(), width, opt->rect.height()));
5615 }
5616 break;
5617
5618 case CC_TitleBar:
5619 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5620 QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
5621 if (!subRule.hasDrawable() && !subRule.hasBox() && !subRule.hasBorder())
5622 break;
5623 QHash<QStyle::SubControl, QRect> layoutRects = titleBarLayout(w, tb);
5624 return layoutRects.value(sc);
5625 }
5626 break;
5627
5628 default:
5629 break;
5630 }
5631
5632 return baseStyle()->subControlRect(cc, opt, sc, w);
5633}
5634
5635QRect QStyleSheetStyle::subElementRect(SubElement se, const QStyleOption *opt, const QWidget *w) const
5636{
5637 RECURSION_GUARD(return baseStyle()->subElementRect(se, opt, w))
5638
5639 QRenderRule rule = renderRule(w, opt);
5640#ifndef QT_NO_TABBAR
5641 int pe = PseudoElement_None;
5642#endif
5643
5644 switch (se) {
5645 case SE_PushButtonContents:
5646 case SE_PushButtonFocusRect:
5647 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
5648 QStyleOptionButton btnOpt(*btn);
5649 if (rule.hasBox() || !rule.hasNativeBorder())
5650 return visualRect(opt->direction, opt->rect, rule.contentsRect(opt->rect));
5651 return rule.baseStyleCanDraw() ? baseStyle()->subElementRect(se, &btnOpt, w)
5652 : QWindowsStyle::subElementRect(se, &btnOpt, w);
5653 }
5654 break;
5655
5656 case SE_LineEditContents:
5657 case SE_FrameContents:
5658 case SE_ShapedFrameContents:
5659 if (rule.hasBox() || !rule.hasNativeBorder()) {
5660 return visualRect(opt->direction, opt->rect, rule.contentsRect(opt->rect));
5661 }
5662 break;
5663
5664 case SE_CheckBoxIndicator:
5665 case SE_RadioButtonIndicator:
5666 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
5667 PseudoElement pe = se == SE_CheckBoxIndicator ? PseudoElement_Indicator : PseudoElement_ExclusiveIndicator;
5668 QRenderRule subRule = renderRule(w, opt, pe);
5669 return positionRect(w, rule, subRule, pe, opt->rect, opt->direction);
5670 }
5671 break;
5672
5673 case SE_CheckBoxContents:
5674 case SE_RadioButtonContents:
5675 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
5676 bool isRadio = se == SE_RadioButtonContents;
5677 QRect ir = subElementRect(isRadio ? SE_RadioButtonIndicator : SE_CheckBoxIndicator,
5678 opt, w);
5679 ir = visualRect(opt->direction, opt->rect, ir);
5680 int spacing = pixelMetric(isRadio ? PM_RadioButtonLabelSpacing : PM_CheckBoxLabelSpacing, 0, w);
5681 QRect cr = rule.contentsRect(opt->rect);
5682 ir.setRect(ir.left() + ir.width() + spacing, cr.y(),
5683 cr.width() - ir.width() - spacing, cr.height());
5684 return visualRect(opt->direction, opt->rect, ir);
5685 }
5686 break;
5687
5688 case SE_ToolBoxTabContents:
5689 if (w && hasStyleRule(w->parentWidget(), PseudoElement_ToolBoxTab)) {
5690 QRenderRule subRule = renderRule(w->parentWidget(), opt, PseudoElement_ToolBoxTab);
5691 return visualRect(opt->direction, opt->rect, subRule.contentsRect(opt->rect));
5692 }
5693 break;
5694
5695 case SE_RadioButtonFocusRect:
5696 case SE_RadioButtonClickRect: // focusrect | indicator
5697 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
5698 return opt->rect;
5699 }
5700 break;
5701
5702 case SE_CheckBoxFocusRect:
5703 case SE_CheckBoxClickRect: // relies on indicator and contents
5704 return ParentStyle::subElementRect(se, opt, w);
5705
5706#ifndef QT_NO_ITEMVIEWS
5707 case SE_ViewItemCheckIndicator:
5708 if (!qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) {
5709 return subElementRect(SE_CheckBoxIndicator, opt, w);
5710 }
5711 // intentionally falls through
5712 case SE_ItemViewItemText:
5713 case SE_ItemViewItemDecoration:
5714 case SE_ItemViewItemFocusRect:
5715 if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) {
5716 QRenderRule subRule = renderRule(w, opt, PseudoElement_ViewItem);
5717 QStyleOptionViewItemV4 optCopy(*vopt);
5718 optCopy.rect = subRule.contentsRect(vopt->rect);
5719 QRect rect = ParentStyle::subElementRect(se, &optCopy, w);
5720 PseudoElement pe = PseudoElement_None;
5721 if (se == SE_ItemViewItemText || se == SE_ItemViewItemFocusRect)
5722 pe = PseudoElement_ViewItemText;
5723 else if (se == SE_ItemViewItemDecoration && vopt->features & QStyleOptionViewItemV2::HasDecoration)
5724 pe = PseudoElement_ViewItemIcon;
5725 else if (se == SE_ItemViewItemCheckIndicator && vopt->features & QStyleOptionViewItemV2::HasCheckIndicator)
5726 pe = PseudoElement_ViewItemIndicator;
5727 else
5728 break;
5729 QRenderRule subRule2 = renderRule(w, opt, pe);
5730 return positionRect(w, subRule2, pe, rect, opt->direction);
5731 }
5732 break;
5733#endif // QT_NO_ITEMVIEWS
5734
5735 case SE_HeaderArrow: {
5736 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewUpArrow);
5737 if (subRule.hasPosition() || subRule.hasGeometry())
5738 return positionRect(w, rule, subRule, PseudoElement_HeaderViewUpArrow, opt->rect, opt->direction);
5739 }
5740 break;
5741
5742 case SE_HeaderLabel: {
5743 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
5744 if (subRule.hasBox() || !subRule.hasNativeBorder())
5745 return subRule.contentsRect(opt->rect);
5746 }
5747 break;
5748
5749 case SE_ProgressBarGroove:
5750 case SE_ProgressBarContents:
5751 case SE_ProgressBarLabel:
5752 if (const QStyleOptionProgressBarV2 *pb = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(opt)) {
5753 if (rule.hasBox() || !rule.hasNativeBorder() || rule.hasPosition() || hasStyleRule(w, PseudoElement_ProgressBarChunk)) {
5754 if (se == SE_ProgressBarGroove)
5755 return rule.borderRect(pb->rect);
5756 else if (se == SE_ProgressBarContents)
5757 return rule.contentsRect(pb->rect);
5758
5759 QSize sz = pb->fontMetrics.size(0, pb->text);
5760 return QStyle::alignedRect(Qt::LeftToRight, rule.hasPosition() ? rule.position()->textAlignment : pb->textAlignment,
5761 sz, pb->rect);
5762 }
5763 }
5764 break;
5765
5766#ifndef QT_NO_TABBAR
5767 case SE_TabWidgetLeftCorner:
5768 pe = PseudoElement_TabWidgetLeftCorner;
5769 // intentionally falls through
5770 case SE_TabWidgetRightCorner:
5771 if (pe == PseudoElement_None)
5772 pe = PseudoElement_TabWidgetRightCorner;
5773 // intentionally falls through
5774 case SE_TabWidgetTabBar:
5775 if (pe == PseudoElement_None)
5776 pe = PseudoElement_TabWidgetTabBar;
5777 // intentionally falls through
5778 case SE_TabWidgetTabPane:
5779 case SE_TabWidgetTabContents:
5780 if (pe == PseudoElement_None)
5781 pe = PseudoElement_TabWidgetPane;
5782
5783 if (hasStyleRule(w, pe)) {
5784 QRect r = QWindowsStyle::subElementRect(pe == PseudoElement_TabWidgetPane ? SE_TabWidgetTabPane : se, opt, w);
5785 QRenderRule subRule = renderRule(w, opt, pe);
5786 r = positionRect(w, subRule, pe, r, opt->direction);
5787 if (pe == PseudoElement_TabWidgetTabBar) {
5788 Q_ASSERT(opt);
5789 r = opt->rect.intersected(r);
5790 }
5791 if (se == SE_TabWidgetTabContents)
5792 r = subRule.contentsRect(r);
5793 return r;
5794 }
5795 break;
5796
5797 case SE_TabBarTearIndicator: {
5798 QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTear);
5799 if (subRule.hasContentsSize()) {
5800 QRect r;
5801 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
5802 switch (tab->shape) {
5803 case QTabBar::RoundedNorth:
5804 case QTabBar::TriangularNorth:
5805 case QTabBar::RoundedSouth:
5806 case QTabBar::TriangularSouth:
5807 r.setRect(tab->rect.left(), tab->rect.top(), subRule.size().width(), opt->rect.height());
5808 break;
5809 case QTabBar::RoundedWest:
5810 case QTabBar::TriangularWest:
5811 case QTabBar::RoundedEast:
5812 case QTabBar::TriangularEast:
5813 r.setRect(tab->rect.left(), tab->rect.top(), opt->rect.width(), subRule.size().height());
5814 break;
5815 default:
5816 break;
5817 }
5818 r = visualRect(opt->direction, opt->rect, r);
5819 }
5820 return r;
5821 }
5822 break;
5823 }
5824#endif // QT_NO_TABBAR
5825
5826 case SE_DockWidgetCloseButton:
5827 case SE_DockWidgetFloatButton: {
5828 PseudoElement pe = (se == SE_DockWidgetCloseButton) ? PseudoElement_DockWidgetCloseButton : PseudoElement_DockWidgetFloatButton;
5829 QRenderRule subRule2 = renderRule(w, opt, pe);
5830 if (!subRule2.hasPosition())
5831 break;
5832 QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetTitle);
5833 return positionRect(w, subRule, subRule2, pe, opt->rect, opt->direction);
5834 }
5835
5836 default:
5837 break;
5838 }
5839
5840 return baseStyle()->subElementRect(se, opt, w);
5841}
5842
5843bool QStyleSheetStyle::event(QEvent *e)
5844{
5845 return baseStyle()->event(e) || ParentStyle::event(e);
5846}
5847
5848void QStyleSheetStyle::updateStyleSheetFont(QWidget* w) const
5849{
5850 QWidget *container = containerWidget(w);
5851 QRenderRule rule = renderRule(container, PseudoElement_None,
5852 PseudoClass_Active | PseudoClass_Enabled | extendedPseudoClass(container));
5853 QFont font = rule.font.resolve(w->font());
5854
5855 if ((!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
5856 && isNaturalChild(w) && qobject_cast<QWidget *>(w->parent())) {
5857
5858 font = font.resolve(static_cast<QWidget *>(w->parent())->font());
5859 }
5860
5861 if (w->data->fnt == font)
5862 return;
5863
5864#ifdef QT3_SUPPORT
5865 QFont old = w->data->fnt;
5866#endif
5867 w->data->fnt = font;
5868#if defined(Q_WS_X11)
5869 // make sure the font set on this widget is associated with the correct screen
5870 //w->data->fnt.x11SetScreen(w->d_func()->xinfo.screen());
5871#endif
5872
5873 QEvent e(QEvent::FontChange);
5874 QApplication::sendEvent(w, &e);
5875#ifdef QT3_SUPPORT
5876 w->fontChange(old);
5877#endif
5878}
5879
5880void QStyleSheetStyle::saveWidgetFont(QWidget* w, const QFont& font) const
5881{
5882 w->setProperty("_q_styleSheetWidgetFont", font);
5883}
5884
5885void QStyleSheetStyle::clearWidgetFont(QWidget* w) const
5886{
5887 w->setProperty("_q_styleSheetWidgetFont", QVariant(QVariant::Invalid));
5888}
5889
5890// Returns the palette that should be used when the particular widget is focused.
5891// This needs to be called by some widgets that do drawing themselves instead
5892// of through the style.
5893// ### This should be removed ideally by Qt 4.5, and at least by Qt 5, and fixed
5894// for good by letting the style draw everything.
5895// Returns true if there is a new palette in pal.
5896bool QStyleSheetStyle::focusPalette(const QWidget* w, const QStyleOption* opt, QPalette* pal)
5897{
5898 if (!w || !opt || !pal)
5899 return false;
5900
5901 RECURSION_GUARD(return false)
5902
5903 w = containerWidget(w);
5904
5905 QRenderRule rule = renderRule(w, PseudoElement_None, pseudoClass(opt->state) | extendedPseudoClass(w));
5906 if (!rule.hasPalette())
5907 return false;
5908
5909 rule.configurePalette(pal, QPalette::NoRole, QPalette::NoRole);
5910 return true;
5911}
5912
5913Qt::Alignment QStyleSheetStyle::resolveAlignment(Qt::LayoutDirection layDir, Qt::Alignment src)
5914{
5915 if (layDir == Qt::LeftToRight || src & Qt::AlignAbsolute)
5916 return src;
5917
5918 if (src & Qt::AlignLeft) {
5919 src &= ~Qt::AlignLeft;
5920 src |= Qt::AlignRight;
5921 } else if (src & Qt::AlignRight) {
5922 src &= ~Qt::AlignRight;
5923 src |= Qt::AlignLeft;
5924 }
5925 src |= Qt::AlignAbsolute;
5926 return src;
5927}
5928
5929// Returns whether the given QWidget has a "natural" parent, meaning that
5930// the parent contains this child as part of its normal operation.
5931// An example is the QTabBar inside a QTabWidget.
5932// This does not mean that any QTabBar which is a child of QTabWidget will
5933// match, only the one that was created by the QTabWidget initialization
5934// (and hence has the correct object name).
5935bool QStyleSheetStyle::isNaturalChild(const QWidget *w)
5936{
5937 if (w->objectName().startsWith(QLatin1String("qt_")))
5938 return true;
5939
5940 return false;
5941}
5942
5943QT_END_NAMESPACE
5944
5945#include "moc_qstylesheetstyle_p.cpp"
5946
5947#endif // QT_NO_STYLE_STYLESHEET
Note: See TracBrowser for help on using the repository browser.