1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtWidgets module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qcommonstyle.h"
41#include "qcommonstyle_p.h"
42
43#include <qfile.h>
44#if QT_CONFIG(itemviews)
45#include <qabstractitemview.h>
46#endif
47#include <qapplication.h>
48#include <private/qguiapplication_p.h>
49#include <qpa/qplatformtheme.h>
50#include <qbitmap.h>
51#include <qcache.h>
52#if QT_CONFIG(dockwidget)
53#include <qdockwidget.h>
54#endif
55#include <qdrawutil.h>
56#if QT_CONFIG(dialogbuttonbox)
57#include <qdialogbuttonbox.h>
58#endif
59#if QT_CONFIG(formlayout)
60#include <qformlayout.h>
61#else
62#include <qlayout.h>
63#endif
64#if QT_CONFIG(groupbox)
65#include <qgroupbox.h>
66#endif
67#include <qmath.h>
68#if QT_CONFIG(menu)
69#include <qmenu.h>
70#endif
71#include <qpainter.h>
72#include <qpaintengine.h>
73#include <qpainterpath.h>
74#if QT_CONFIG(slider)
75#include <qslider.h>
76#endif
77#include <qstyleoption.h>
78#if QT_CONFIG(tabbar)
79#include <qtabbar.h>
80#endif
81#if QT_CONFIG(tabwidget)
82#include <qtabwidget.h>
83#endif
84#if QT_CONFIG(toolbar)
85#include <qtoolbar.h>
86#endif
87#if QT_CONFIG(toolbutton)
88#include <qtoolbutton.h>
89#endif
90#if QT_CONFIG(rubberband)
91#include <qrubberband.h>
92#endif
93#if QT_CONFIG(treeview)
94#include "qtreeview.h"
95#endif
96#include <private/qcommonstylepixmaps_p.h>
97#include <private/qmath_p.h>
98#include <qdebug.h>
99#include <qtextformat.h>
100#if QT_CONFIG(wizard)
101#include <qwizard.h>
102#endif
103#if QT_CONFIG(filedialog)
104#include <qsidebar_p.h>
105#endif
106#include <qfileinfo.h>
107#include <qdir.h>
108#if QT_CONFIG(settings)
109#include <qsettings.h>
110#endif
111#include <qvariant.h>
112#include <qpixmapcache.h>
113#if QT_CONFIG(animation)
114#include <private/qstyleanimation_p.h>
115#endif
116
117#include <limits.h>
118
119#include <private/qtextengine_p.h>
120#include <private/qstylehelper_p.h>
121
122QT_BEGIN_NAMESPACE
123
124static QWindow *qt_getWindow(const QWidget *widget)
125{
126 return widget ? widget->window()->windowHandle() : 0;
127}
128
129/*!
130 \class QCommonStyle
131 \brief The QCommonStyle class encapsulates the common Look and Feel of a GUI.
132
133 \ingroup appearance
134 \inmodule QtWidgets
135
136 This abstract class implements some of the widget's look and feel
137 that is common to all GUI styles provided and shipped as part of
138 Qt.
139
140 Since QCommonStyle inherits QStyle, all of its functions are fully documented
141 in the QStyle documentation.
142 \omit
143 , although the
144 extra functions that QCommonStyle provides, e.g.
145 drawComplexControl(), drawControl(), drawPrimitive(),
146 hitTestComplexControl(), subControlRect(), sizeFromContents(), and
147 subElementRect() are documented here.
148 \endomit
149
150 \sa QStyle, QProxyStyle
151*/
152
153/*!
154 Constructs a QCommonStyle.
155*/
156QCommonStyle::QCommonStyle()
157 : QStyle(*new QCommonStylePrivate)
158{ }
159
160/*! \internal
161*/
162QCommonStyle::QCommonStyle(QCommonStylePrivate &dd)
163 : QStyle(dd)
164{ }
165
166/*!
167 Destroys the style.
168*/
169QCommonStyle::~QCommonStyle()
170{ }
171
172
173/*!
174 \reimp
175*/
176void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
177 const QWidget *widget) const
178{
179 Q_D(const QCommonStyle);
180 switch (pe) {
181 case PE_FrameButtonBevel:
182 case PE_FrameButtonTool:
183 qDrawShadeRect(p, opt->rect, opt->palette,
184 opt->state & (State_Sunken | State_On), 1, 0);
185 break;
186 case PE_PanelButtonCommand:
187 case PE_PanelButtonBevel:
188 case PE_PanelButtonTool:
189 case PE_IndicatorButtonDropDown:
190 qDrawShadePanel(p, opt->rect, opt->palette,
191 opt->state & (State_Sunken | State_On), 1,
192 &opt->palette.brush(QPalette::Button));
193 break;
194 case PE_IndicatorItemViewItemCheck:
195 proxy()->drawPrimitive(PE_IndicatorCheckBox, opt, p, widget);
196 break;
197 case PE_IndicatorCheckBox:
198 if (opt->state & State_NoChange) {
199 p->setPen(opt->palette.windowText().color());
200 p->fillRect(opt->rect, opt->palette.brush(QPalette::Button));
201 p->drawRect(opt->rect);
202 p->drawLine(opt->rect.topLeft(), opt->rect.bottomRight());
203 } else {
204 qDrawShadePanel(p, opt->rect.x(), opt->rect.y(), opt->rect.width(), opt->rect.height(),
205 opt->palette, opt->state & (State_Sunken | State_On), 1,
206 &opt->palette.brush(QPalette::Button));
207 }
208 break;
209 case PE_IndicatorRadioButton: {
210 QRect ir = opt->rect;
211 p->setPen(opt->palette.dark().color());
212 p->drawArc(opt->rect, 0, 5760);
213 if (opt->state & (State_Sunken | State_On)) {
214 ir.adjust(2, 2, -2, -2);
215 p->setBrush(opt->palette.windowText());
216 bool oldQt4CompatiblePainting = p->testRenderHint(QPainter::Qt4CompatiblePainting);
217 p->setRenderHint(QPainter::Qt4CompatiblePainting);
218 p->drawEllipse(ir);
219 p->setRenderHint(QPainter::Qt4CompatiblePainting, oldQt4CompatiblePainting);
220 }
221 break; }
222 case PE_FrameFocusRect:
223 if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(opt)) {
224 QColor bg = fropt->backgroundColor;
225 QPen oldPen = p->pen();
226 if (bg.isValid()) {
227 int h, s, v;
228 bg.getHsv(&h, &s, &v);
229 if (v >= 128)
230 p->setPen(Qt::black);
231 else
232 p->setPen(Qt::white);
233 } else {
234 p->setPen(opt->palette.windowText().color());
235 }
236 QRect focusRect = opt->rect.adjusted(1, 1, -1, -1);
237 p->drawRect(focusRect.adjusted(0, 0, -1, -1)); //draw pen inclusive
238 p->setPen(oldPen);
239 }
240 break;
241 case PE_IndicatorMenuCheckMark: {
242 const int markW = opt->rect.width() > 7 ? 7 : opt->rect.width();
243 const int markH = markW;
244 int posX = opt->rect.x() + (opt->rect.width() - markW)/2 + 1;
245 int posY = opt->rect.y() + (opt->rect.height() - markH)/2;
246
247 QVector<QLineF> a;
248 a.reserve(markH);
249
250 int i, xx, yy;
251 xx = posX;
252 yy = 3 + posY;
253 for (i = 0; i < markW/2; ++i) {
254 a << QLineF(xx, yy, xx, yy + 2);
255 ++xx;
256 ++yy;
257 }
258 yy -= 2;
259 for (; i < markH; ++i) {
260 a << QLineF(xx, yy, xx, yy + 2);
261 ++xx;
262 --yy;
263 }
264 if (!(opt->state & State_Enabled) && !(opt->state & State_On)) {
265 p->save();
266 p->translate(1, 1);
267 p->setPen(opt->palette.light().color());
268 p->drawLines(a);
269 p->restore();
270 }
271 p->setPen((opt->state & State_On) ? opt->palette.highlightedText().color() : opt->palette.text().color());
272 p->drawLines(a);
273 break; }
274 case PE_Frame:
275 case PE_FrameMenu:
276 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
277 if (pe == PE_FrameMenu || (frame->state & State_Sunken) || (frame->state & State_Raised)) {
278 qDrawShadePanel(p, frame->rect, frame->palette, frame->state & State_Sunken,
279 frame->lineWidth);
280 } else {
281 qDrawPlainRect(p, frame->rect, frame->palette.windowText().color(), frame->lineWidth);
282 }
283 }
284 break;
285#if QT_CONFIG(toolbar)
286 case PE_PanelMenuBar:
287 if (widget && qobject_cast<QToolBar *>(widget->parentWidget()))
288 break;
289 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)){
290 qDrawShadePanel(p, frame->rect, frame->palette, false, frame->lineWidth,
291 &frame->palette.brush(QPalette::Button));
292
293 }
294 else if (const QStyleOptionToolBar *frame = qstyleoption_cast<const QStyleOptionToolBar *>(opt)){
295 qDrawShadePanel(p, frame->rect, frame->palette, false, frame->lineWidth,
296 &frame->palette.brush(QPalette::Button));
297 }
298
299 break;
300 case PE_PanelMenu:
301 break;
302 case PE_PanelToolBar:
303 break;
304#endif // QT_CONFIG(toolbar)
305#if QT_CONFIG(progressbar)
306 case PE_IndicatorProgressChunk:
307 {
308 bool vertical = false;
309 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt))
310 vertical = pb->orientation == Qt::Vertical;
311 if (!vertical) {
312 p->fillRect(opt->rect.x(), opt->rect.y() + 3, opt->rect.width() -2, opt->rect.height() - 6,
313 opt->palette.brush(QPalette::Highlight));
314 } else {
315 p->fillRect(opt->rect.x() + 2, opt->rect.y(), opt->rect.width() -6, opt->rect.height() - 2,
316 opt->palette.brush(QPalette::Highlight));
317 }
318 }
319 break;
320#endif // QT_CONFIG(progressbar)
321 case PE_IndicatorBranch: {
322 static const int decoration_size = 9;
323 int mid_h = opt->rect.x() + opt->rect.width() / 2;
324 int mid_v = opt->rect.y() + opt->rect.height() / 2;
325 int bef_h = mid_h;
326 int bef_v = mid_v;
327 int aft_h = mid_h;
328 int aft_v = mid_v;
329 if (opt->state & State_Children) {
330 int delta = decoration_size / 2;
331 bef_h -= delta;
332 bef_v -= delta;
333 aft_h += delta;
334 aft_v += delta;
335 p->drawLine(bef_h + 2, bef_v + 4, bef_h + 6, bef_v + 4);
336 if (!(opt->state & State_Open))
337 p->drawLine(bef_h + 4, bef_v + 2, bef_h + 4, bef_v + 6);
338 QPen oldPen = p->pen();
339 p->setPen(opt->palette.dark().color());
340 p->drawRect(bef_h, bef_v, decoration_size - 1, decoration_size - 1);
341 p->setPen(oldPen);
342 }
343 QBrush brush(opt->palette.dark().color(), Qt::Dense4Pattern);
344 if (opt->state & State_Item) {
345 if (opt->direction == Qt::RightToLeft)
346 p->fillRect(opt->rect.left(), mid_v, bef_h - opt->rect.left(), 1, brush);
347 else
348 p->fillRect(aft_h, mid_v, opt->rect.right() - aft_h + 1, 1, brush);
349 }
350 if (opt->state & State_Sibling)
351 p->fillRect(mid_h, aft_v, 1, opt->rect.bottom() - aft_v + 1, brush);
352 if (opt->state & (State_Open | State_Children | State_Item | State_Sibling))
353 p->fillRect(mid_h, opt->rect.y(), 1, bef_v - opt->rect.y(), brush);
354 break; }
355 case PE_FrameStatusBarItem:
356 qDrawShadeRect(p, opt->rect, opt->palette, true, 1, 0, 0);
357 break;
358 case PE_IndicatorHeaderArrow:
359 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
360 QPen oldPen = p->pen();
361 if (header->sortIndicator & QStyleOptionHeader::SortUp) {
362 p->setPen(QPen(opt->palette.light(), 0));
363 p->drawLine(opt->rect.x() + opt->rect.width(), opt->rect.y(),
364 opt->rect.x() + opt->rect.width() / 2, opt->rect.y() + opt->rect.height());
365 p->setPen(QPen(opt->palette.dark(), 0));
366 const QPoint points[] = {
367 QPoint(opt->rect.x() + opt->rect.width() / 2, opt->rect.y() + opt->rect.height()),
368 QPoint(opt->rect.x(), opt->rect.y()),
369 QPoint(opt->rect.x() + opt->rect.width(), opt->rect.y()),
370 };
371 p->drawPolyline(points, sizeof points / sizeof *points);
372 } else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
373 p->setPen(QPen(opt->palette.light(), 0));
374 const QPoint points[] = {
375 QPoint(opt->rect.x(), opt->rect.y() + opt->rect.height()),
376 QPoint(opt->rect.x() + opt->rect.width(), opt->rect.y() + opt->rect.height()),
377 QPoint(opt->rect.x() + opt->rect.width() / 2, opt->rect.y()),
378 };
379 p->drawPolyline(points, sizeof points / sizeof *points);
380 p->setPen(QPen(opt->palette.dark(), 0));
381 p->drawLine(opt->rect.x(), opt->rect.y() + opt->rect.height(),
382 opt->rect.x() + opt->rect.width() / 2, opt->rect.y());
383 }
384 p->setPen(oldPen);
385 }
386 break;
387#if QT_CONFIG(tabbar)
388 case PE_FrameTabBarBase:
389 if (const QStyleOptionTabBarBase *tbb
390 = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
391 p->save();
392 switch (tbb->shape) {
393 case QTabBar::RoundedNorth:
394 case QTabBar::TriangularNorth:
395 p->setPen(QPen(tbb->palette.light(), 0));
396 p->drawLine(tbb->rect.topLeft(), tbb->rect.topRight());
397 break;
398 case QTabBar::RoundedWest:
399 case QTabBar::TriangularWest:
400 p->setPen(QPen(tbb->palette.light(), 0));
401 p->drawLine(tbb->rect.topLeft(), tbb->rect.bottomLeft());
402 break;
403 case QTabBar::RoundedSouth:
404 case QTabBar::TriangularSouth:
405 p->setPen(QPen(tbb->palette.shadow(), 0));
406 p->drawLine(tbb->rect.left(), tbb->rect.bottom(),
407 tbb->rect.right(), tbb->rect.bottom());
408 p->setPen(QPen(tbb->palette.dark(), 0));
409 p->drawLine(tbb->rect.left(), tbb->rect.bottom() - 1,
410 tbb->rect.right() - 1, tbb->rect.bottom() - 1);
411 break;
412 case QTabBar::RoundedEast:
413 case QTabBar::TriangularEast:
414 p->setPen(QPen(tbb->palette.dark(), 0));
415 p->drawLine(tbb->rect.topRight(), tbb->rect.bottomRight());
416 break;
417 }
418 p->restore();
419 }
420 break;
421 case PE_IndicatorTabClose: {
422 if (d->tabBarcloseButtonIcon.isNull()) {
423 d->tabBarcloseButtonIcon.addPixmap(QPixmap(
424 QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-closetab-16.png")),
425 QIcon::Normal, QIcon::Off);
426 d->tabBarcloseButtonIcon.addPixmap(QPixmap(
427 QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-closetab-down-16.png")),
428 QIcon::Normal, QIcon::On);
429 d->tabBarcloseButtonIcon.addPixmap(QPixmap(
430 QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-closetab-hover-16.png")),
431 QIcon::Active, QIcon::Off);
432 }
433
434 int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize);
435 QIcon::Mode mode = opt->state & State_Enabled ?
436 (opt->state & State_Raised ? QIcon::Active : QIcon::Normal)
437 : QIcon::Disabled;
438 if (!(opt->state & State_Raised)
439 && !(opt->state & State_Sunken)
440 && !(opt->state & QStyle::State_Selected))
441 mode = QIcon::Disabled;
442
443 QIcon::State state = opt->state & State_Sunken ? QIcon::On : QIcon::Off;
444 QPixmap pixmap = d->tabBarcloseButtonIcon.pixmap(qt_getWindow(widget), QSize(size, size), mode, state);
445 proxy()->drawItemPixmap(p, opt->rect, Qt::AlignCenter, pixmap);
446 break;
447 }
448#else
449 Q_UNUSED(d);
450#endif // QT_CONFIG(tabbar)
451 case PE_FrameTabWidget:
452 case PE_FrameWindow:
453 qDrawWinPanel(p, opt->rect, opt->palette, false, 0);
454 break;
455 case PE_FrameLineEdit:
456 proxy()->drawPrimitive(PE_Frame, opt, p, widget);
457 break;
458#if QT_CONFIG(groupbox)
459 case PE_FrameGroupBox:
460 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
461 if (frame->features & QStyleOptionFrame::Flat) {
462 QRect fr = frame->rect;
463 QPoint p1(fr.x(), fr.y() + 1);
464 QPoint p2(fr.x() + fr.width(), p1.y());
465 qDrawShadeLine(p, p1, p2, frame->palette, true,
466 frame->lineWidth, frame->midLineWidth);
467 } else {
468 qDrawShadeRect(p, frame->rect.x(), frame->rect.y(), frame->rect.width(),
469 frame->rect.height(), frame->palette, true,
470 frame->lineWidth, frame->midLineWidth);
471 }
472 }
473 break;
474#endif // QT_CONFIG(groupbox)
475#if QT_CONFIG(dockwidget)
476 case PE_FrameDockWidget:
477 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
478 int lw = frame->lineWidth;
479 if (lw <= 0)
480 lw = proxy()->pixelMetric(PM_DockWidgetFrameWidth);
481
482 qDrawShadePanel(p, frame->rect, frame->palette, false, lw);
483 }
484 break;
485#endif // QT_CONFIG(dockwidget)
486#if QT_CONFIG(toolbar)
487 case PE_IndicatorToolBarHandle:
488 p->save();
489 p->translate(opt->rect.x(), opt->rect.y());
490 if (opt->state & State_Horizontal) {
491 int x = opt->rect.width() / 3;
492 if (opt->direction == Qt::RightToLeft)
493 x -= 2;
494 if (opt->rect.height() > 4) {
495 qDrawShadePanel(p, x, 2, 3, opt->rect.height() - 4,
496 opt->palette, false, 1, 0);
497 qDrawShadePanel(p, x+3, 2, 3, opt->rect.height() - 4,
498 opt->palette, false, 1, 0);
499 }
500 } else {
501 if (opt->rect.width() > 4) {
502 int y = opt->rect.height() / 3;
503 qDrawShadePanel(p, 2, y, opt->rect.width() - 4, 3,
504 opt->palette, false, 1, 0);
505 qDrawShadePanel(p, 2, y+3, opt->rect.width() - 4, 3,
506 opt->palette, false, 1, 0);
507 }
508 }
509 p->restore();
510 break;
511 case PE_IndicatorToolBarSeparator:
512 {
513 QPoint p1, p2;
514 if (opt->state & State_Horizontal) {
515 p1 = QPoint(opt->rect.width()/2, 0);
516 p2 = QPoint(p1.x(), opt->rect.height());
517 } else {
518 p1 = QPoint(0, opt->rect.height()/2);
519 p2 = QPoint(opt->rect.width(), p1.y());
520 }
521 qDrawShadeLine(p, p1, p2, opt->palette, 1, 1, 0);
522 break;
523 }
524#endif // QT_CONFIG(toolbar)
525#if QT_CONFIG(spinbox)
526 case PE_IndicatorSpinPlus:
527 case PE_IndicatorSpinMinus: {
528 QRect r = opt->rect;
529 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
530 QRect br = r.adjusted(fw, fw, -fw, -fw);
531
532 int offset = (opt->state & State_Sunken) ? 1 : 0;
533 int step = (br.width() + 4) / 5;
534 p->fillRect(br.x() + offset, br.y() + offset +br.height() / 2 - step / 2,
535 br.width(), step,
536 opt->palette.buttonText());
537 if (pe == PE_IndicatorSpinPlus)
538 p->fillRect(br.x() + br.width() / 2 - step / 2 + offset, br.y() + offset,
539 step, br.height(),
540 opt->palette.buttonText());
541
542 break; }
543 case PE_IndicatorSpinUp:
544 case PE_IndicatorSpinDown: {
545 QRect r = opt->rect;
546 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
547 // QRect br = r.adjusted(fw, fw, -fw, -fw);
548 int x = r.x(), y = r.y(), w = r.width(), h = r.height();
549 int sw = w-4;
550 if (sw < 3)
551 break;
552 else if (!(sw & 1))
553 sw--;
554 sw -= (sw / 7) * 2; // Empty border
555 int sh = sw/2 + 2; // Must have empty row at foot of arrow
556
557 int sx = x + w / 2 - sw / 2;
558 int sy = y + h / 2 - sh / 2;
559
560 if (pe == PE_IndicatorSpinUp && fw)
561 --sy;
562
563 int bsx = 0;
564 int bsy = 0;
565 if (opt->state & State_Sunken) {
566 bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal);
567 bsy = proxy()->pixelMetric(PM_ButtonShiftVertical);
568 }
569 p->save();
570 p->translate(sx + bsx, sy + bsy);
571 p->setPen(opt->palette.buttonText().color());
572 p->setBrush(opt->palette.buttonText());
573 p->setRenderHint(QPainter::Qt4CompatiblePainting);
574 if (pe == PE_IndicatorSpinDown) {
575 const QPoint points[] = { QPoint(0, 1), QPoint(sw-1, 1), QPoint(sh-2, sh-1) };
576 p->drawPolygon(points, sizeof points / sizeof *points);
577 } else {
578 const QPoint points[] = { QPoint(0, sh-1), QPoint(sw-1, sh-1), QPoint(sh-2, 1) };
579 p->drawPolygon(points, sizeof points / sizeof *points);
580 }
581 p->restore();
582 break; }
583#endif // QT_CONFIG(spinbox)
584 case PE_PanelTipLabel: {
585 const QBrush brush(opt->palette.toolTipBase());
586 qDrawPlainRect(p, opt->rect, opt->palette.toolTipText().color(), 1, &brush);
587 break;
588 }
589#if QT_CONFIG(tabbar)
590 case PE_IndicatorTabTear:
591 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
592 bool rtl = tab->direction == Qt::RightToLeft;
593 const bool horizontal = tab->rect.height() > tab->rect.width();
594 const int margin = 4;
595 QPainterPath path;
596
597 if (horizontal) {
598 QRect rect = tab->rect.adjusted(rtl ? margin : 0, 0, rtl ? 1 : -margin, 0);
599 rect.setTop(rect.top() + ((tab->state & State_Selected) ? 1 : 3));
600 rect.setBottom(rect.bottom() - ((tab->state & State_Selected) ? 0 : 2));
601
602 path.moveTo(QPoint(rtl ? rect.right() : rect.left(), rect.top()));
603 int count = 4;
604 for (int jags = 1; jags <= count; ++jags, rtl = !rtl)
605 path.lineTo(QPoint(rtl ? rect.left() : rect.right(), rect.top() + jags * rect.height()/count));
606 } else {
607 QRect rect = tab->rect.adjusted(0, 0, 0, -margin);
608 rect.setLeft(rect.left() + ((tab->state & State_Selected) ? 1 : 3));
609 rect.setRight(rect.right() - ((tab->state & State_Selected) ? 0 : 2));
610
611 path.moveTo(QPoint(rect.left(), rect.top()));
612 int count = 4;
613 for (int jags = 1; jags <= count; ++jags, rtl = !rtl)
614 path.lineTo(QPoint(rect.left() + jags * rect.width()/count, rtl ? rect.top() : rect.bottom()));
615 }
616
617 p->setPen(QPen(tab->palette.dark(), qreal(.8)));
618 p->setBrush(tab->palette.window());
619 p->setRenderHint(QPainter::Antialiasing);
620 p->drawPath(path);
621 }
622 break;
623#endif // QT_CONFIG(tabbar)
624#if QT_CONFIG(lineedit)
625 case PE_PanelLineEdit:
626 if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
627 p->fillRect(panel->rect.adjusted(panel->lineWidth, panel->lineWidth, -panel->lineWidth, -panel->lineWidth),
628 panel->palette.brush(QPalette::Base));
629
630 if (panel->lineWidth > 0)
631 proxy()->drawPrimitive(PE_FrameLineEdit, panel, p, widget);
632 }
633 break;
634#endif // QT_CONFIG(lineedit)
635#if QT_CONFIG(columnview)
636 case PE_IndicatorColumnViewArrow: {
637 if (const QStyleOptionViewItem *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
638 bool reverse = (viewOpt->direction == Qt::RightToLeft);
639 p->save();
640 QPainterPath path;
641 int x = viewOpt->rect.x() + 1;
642 int offset = (viewOpt->rect.height() / 3);
643 int height = (viewOpt->rect.height()) - offset * 2;
644 if (height % 2 == 1)
645 --height;
646 int x2 = x + height - 1;
647 if (reverse) {
648 x = viewOpt->rect.x() + viewOpt->rect.width() - 1;
649 x2 = x - height + 1;
650 }
651 path.moveTo(x, viewOpt->rect.y() + offset);
652 path.lineTo(x, viewOpt->rect.y() + offset + height);
653 path.lineTo(x2, viewOpt->rect.y() + offset+height/2);
654 path.closeSubpath();
655 if (viewOpt->state & QStyle::State_Selected ) {
656 if (viewOpt->showDecorationSelected) {
657 QColor color = viewOpt->palette.color(QPalette::Active, QPalette::HighlightedText);
658 p->setPen(color);
659 p->setBrush(color);
660 } else {
661 QColor color = viewOpt->palette.color(QPalette::Active, QPalette::WindowText);
662 p->setPen(color);
663 p->setBrush(color);
664 }
665
666 } else {
667 QColor color = viewOpt->palette.color(QPalette::Active, QPalette::Mid);
668 p->setPen(color);
669 p->setBrush(color);
670 }
671 p->drawPath(path);
672
673 // draw the vertical and top triangle line
674 if (!(viewOpt->state & QStyle::State_Selected)) {
675 QPainterPath lines;
676 lines.moveTo(x, viewOpt->rect.y() + offset);
677 lines.lineTo(x, viewOpt->rect.y() + offset + height);
678 lines.moveTo(x, viewOpt->rect.y() + offset);
679 lines.lineTo(x2, viewOpt->rect.y() + offset+height/2);
680 QColor color = viewOpt->palette.color(QPalette::Active, QPalette::Dark);
681 p->setPen(color);
682 p->drawPath(lines);
683 }
684 p->restore();
685 }
686 break; }
687#endif //QT_CONFIG(columnview)
688 case PE_IndicatorItemViewItemDrop: {
689 QRect rect = opt->rect;
690 if (opt->rect.height() == 0)
691 p->drawLine(rect.topLeft(), rect.topRight());
692 else
693 p->drawRect(rect);
694 break; }
695#if QT_CONFIG(itemviews)
696 case PE_PanelItemViewRow:
697 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
698 QPalette::ColorGroup cg = (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled))
699 ? QPalette::Normal : QPalette::Disabled;
700 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
701 cg = QPalette::Inactive;
702
703 if ((vopt->state & QStyle::State_Selected) && proxy()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, opt, widget))
704 p->fillRect(vopt->rect, vopt->palette.brush(cg, QPalette::Highlight));
705 else if (vopt->features & QStyleOptionViewItem::Alternate)
706 p->fillRect(vopt->rect, vopt->palette.brush(cg, QPalette::AlternateBase));
707 }
708 break;
709 case PE_PanelItemViewItem:
710 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
711 QPalette::ColorGroup cg = (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled))
712 ? QPalette::Normal : QPalette::Disabled;
713 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
714 cg = QPalette::Inactive;
715
716 if (vopt->showDecorationSelected && (vopt->state & QStyle::State_Selected)) {
717 p->fillRect(vopt->rect, vopt->palette.brush(cg, QPalette::Highlight));
718 } else {
719 if (vopt->backgroundBrush.style() != Qt::NoBrush) {
720 QPointF oldBO = p->brushOrigin();
721 p->setBrushOrigin(vopt->rect.topLeft());
722 p->fillRect(vopt->rect, vopt->backgroundBrush);
723 p->setBrushOrigin(oldBO);
724 }
725
726 if (vopt->state & QStyle::State_Selected) {
727 QRect textRect = subElementRect(QStyle::SE_ItemViewItemText, opt, widget);
728 p->fillRect(textRect, vopt->palette.brush(cg, QPalette::Highlight));
729 }
730 }
731 }
732 break;
733#endif // QT_CONFIG(itemviews)
734 case PE_PanelScrollAreaCorner: {
735 const QBrush brush(opt->palette.brush(QPalette::Window));
736 p->fillRect(opt->rect, brush);
737 } break;
738 case PE_IndicatorArrowUp:
739 case PE_IndicatorArrowDown:
740 case PE_IndicatorArrowRight:
741 case PE_IndicatorArrowLeft:
742 {
743 if (opt->rect.width() <= 1 || opt->rect.height() <= 1)
744 break;
745 QRect r = opt->rect;
746 int size = qMin(r.height(), r.width());
747 QPixmap pixmap;
748 QString pixmapName = QStyleHelper::uniqueName(QLatin1String("$qt_ia-")
749 % QLatin1String(metaObject()->className()), opt, QSize(size, size))
750 % HexString<uint>(pe);
751 if (!QPixmapCache::find(pixmapName, &pixmap)) {
752 qreal pixelRatio = p->device()->devicePixelRatioF();
753 int border = qRound(pixelRatio*(size/5));
754 int sqsize = qRound(pixelRatio*(2*(size/2)));
755 QImage image(sqsize, sqsize, QImage::Format_ARGB32_Premultiplied);
756 image.fill(0);
757 QPainter imagePainter(&image);
758
759 QPolygon a;
760 switch (pe) {
761 case PE_IndicatorArrowUp:
762 a.setPoints(3, border, sqsize/2, sqsize/2, border, sqsize - border, sqsize/2);
763 break;
764 case PE_IndicatorArrowDown:
765 a.setPoints(3, border, sqsize/2, sqsize/2, sqsize - border, sqsize - border, sqsize/2);
766 break;
767 case PE_IndicatorArrowRight:
768 a.setPoints(3, sqsize - border, sqsize/2, sqsize/2, border, sqsize/2, sqsize - border);
769 break;
770 case PE_IndicatorArrowLeft:
771 a.setPoints(3, border, sqsize/2, sqsize/2, border, sqsize/2, sqsize - border);
772 break;
773 default:
774 break;
775 }
776
777 int bsx = 0;
778 int bsy = 0;
779
780 if (opt->state & State_Sunken) {
781 bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
782 bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
783 }
784
785 QRect bounds = a.boundingRect();
786 int sx = sqsize / 2 - bounds.center().x() - 1;
787 int sy = sqsize / 2 - bounds.center().y() - 1;
788 imagePainter.translate(sx + bsx, sy + bsy);
789 imagePainter.setPen(opt->palette.buttonText().color());
790 imagePainter.setBrush(opt->palette.buttonText());
791 imagePainter.setRenderHint(QPainter::Qt4CompatiblePainting);
792
793 if (!(opt->state & State_Enabled)) {
794 imagePainter.translate(1, 1);
795 imagePainter.setBrush(opt->palette.light().color());
796 imagePainter.setPen(opt->palette.light().color());
797 imagePainter.drawPolygon(a);
798 imagePainter.translate(-1, -1);
799 imagePainter.setBrush(opt->palette.mid().color());
800 imagePainter.setPen(opt->palette.mid().color());
801 }
802
803 imagePainter.drawPolygon(a);
804 imagePainter.end();
805 pixmap = QPixmap::fromImage(image);
806 pixmap.setDevicePixelRatio(pixelRatio);
807 QPixmapCache::insert(pixmapName, pixmap);
808 }
809 int xOffset = r.x() + (r.width() - size)/2;
810 int yOffset = r.y() + (r.height() - size)/2;
811 p->drawPixmap(xOffset, yOffset, pixmap);
812 }
813 break;
814 default:
815 break;
816 }
817}
818
819#if QT_CONFIG(toolbutton)
820static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
821 const QRect &rect, QPainter *painter, const QWidget *widget = 0)
822{
823 QStyle::PrimitiveElement pe;
824 switch (toolbutton->arrowType) {
825 case Qt::LeftArrow:
826 pe = QStyle::PE_IndicatorArrowLeft;
827 break;
828 case Qt::RightArrow:
829 pe = QStyle::PE_IndicatorArrowRight;
830 break;
831 case Qt::UpArrow:
832 pe = QStyle::PE_IndicatorArrowUp;
833 break;
834 case Qt::DownArrow:
835 pe = QStyle::PE_IndicatorArrowDown;
836 break;
837 default:
838 return;
839 }
840 QStyleOption arrowOpt = *toolbutton;
841 arrowOpt.rect = rect;
842 style->drawPrimitive(pe, &arrowOpt, painter, widget);
843}
844#endif // QT_CONFIG(toolbutton)
845
846static QSizeF viewItemTextLayout(QTextLayout &textLayout, int lineWidth, int maxHeight = -1, int *lastVisibleLine = nullptr)
847{
848 if (lastVisibleLine)
849 *lastVisibleLine = -1;
850 qreal height = 0;
851 qreal widthUsed = 0;
852 textLayout.beginLayout();
853 int i = 0;
854 while (true) {
855 QTextLine line = textLayout.createLine();
856 if (!line.isValid())
857 break;
858 line.setLineWidth(lineWidth);
859 line.setPosition(QPointF(0, height));
860 height += line.height();
861 widthUsed = qMax(widthUsed, line.naturalTextWidth());
862 // we assume that the height of the next line is the same as the current one
863 if (maxHeight > 0 && lastVisibleLine && height + line.height() > maxHeight) {
864 const QTextLine nextLine = textLayout.createLine();
865 *lastVisibleLine = nextLine.isValid() ? i : -1;
866 break;
867 }
868 ++i;
869 }
870 textLayout.endLayout();
871 return QSizeF(widthUsed, height);
872}
873
874QString QCommonStylePrivate::calculateElidedText(const QString &text, const QTextOption &textOption,
875 const QFont &font, const QRect &textRect, const Qt::Alignment valign,
876 Qt::TextElideMode textElideMode, int flags,
877 bool lastVisibleLineShouldBeElided, QPointF *paintStartPosition) const
878{
879 QTextLayout textLayout(text, font);
880 textLayout.setTextOption(textOption);
881
882 // In AlignVCenter mode when more than one line is displayed and the height only allows
883 // some of the lines it makes no sense to display those. From a users perspective it makes
884 // more sense to see the start of the text instead something inbetween.
885 const bool vAlignmentOptimization = paintStartPosition && valign.testFlag(Qt::AlignVCenter);
886
887 int lastVisibleLine = -1;
888 viewItemTextLayout(textLayout, textRect.width(), vAlignmentOptimization ? textRect.height() : -1, &lastVisibleLine);
889
890 const QRectF boundingRect = textLayout.boundingRect();
891 // don't care about LTR/RTL here, only need the height
892 const QRect layoutRect = QStyle::alignedRect(Qt::LayoutDirectionAuto, valign,
893 boundingRect.size().toSize(), textRect);
894
895 if (paintStartPosition)
896 *paintStartPosition = QPointF(textRect.x(), layoutRect.top());
897
898 QString ret;
899 qreal height = 0;
900 const int lineCount = textLayout.lineCount();
901 for (int i = 0; i < lineCount; ++i) {
902 const QTextLine line = textLayout.lineAt(i);
903 height += line.height();
904
905 // above visible rect
906 if (height + layoutRect.top() <= textRect.top()) {
907 if (paintStartPosition)
908 paintStartPosition->ry() += line.height();
909 continue;
910 }
911
912 const int start = line.textStart();
913 const int length = line.textLength();
914 const bool drawElided = line.naturalTextWidth() > textRect.width();
915 bool elideLastVisibleLine = lastVisibleLine == i;
916 if (!drawElided && i + 1 < lineCount && lastVisibleLineShouldBeElided) {
917 const QTextLine nextLine = textLayout.lineAt(i + 1);
918 const int nextHeight = height + nextLine.height() / 2;
919 // elide when less than the next half line is visible
920 if (nextHeight + layoutRect.top() > textRect.height() + textRect.top())
921 elideLastVisibleLine = true;
922 }
923
924 QString text = textLayout.text().mid(start, length);
925 if (drawElided || elideLastVisibleLine) {
926 if (elideLastVisibleLine) {
927 if (text.endsWith(QChar::LineSeparator))
928 text.chop(1);
929 text += QChar(0x2026);
930 }
931 const QStackTextEngine engine(text, font);
932 ret += engine.elidedText(textElideMode, textRect.width(), flags);
933
934 // no newline for the last line (last visible or real)
935 // sometimes drawElided is true but no eliding is done so the text ends
936 // with QChar::LineSeparator - don't add another one. This happened with
937 // arabic text in the testcase for QTBUG-72805
938 if (i < lineCount - 1 &&
939 !ret.endsWith(QChar::LineSeparator))
940 ret += QChar::LineSeparator;
941 } else {
942 ret += text;
943 }
944
945 // below visible text, can stop
946 if ((height + layoutRect.top() >= textRect.bottom()) ||
947 (lastVisibleLine >= 0 && lastVisibleLine == i))
948 break;
949 }
950 return ret;
951}
952
953#if QT_CONFIG(itemviews)
954
955QSize QCommonStylePrivate::viewItemSize(const QStyleOptionViewItem *option, int role) const
956{
957 const QWidget *widget = option->widget;
958 switch (role) {
959 case Qt::CheckStateRole:
960 if (option->features & QStyleOptionViewItem::HasCheckIndicator)
961 return QSize(proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth, option, widget),
962 proxyStyle->pixelMetric(QStyle::PM_IndicatorHeight, option, widget));
963 break;
964 case Qt::DisplayRole:
965 if (option->features & QStyleOptionViewItem::HasDisplay) {
966 QTextOption textOption;
967 textOption.setWrapMode(QTextOption::WordWrap);
968 QTextLayout textLayout(option->text, option->font);
969 textLayout.setTextOption(textOption);
970 const bool wrapText = option->features & QStyleOptionViewItem::WrapText;
971 const int textMargin = proxyStyle->pixelMetric(QStyle::PM_FocusFrameHMargin, option, widget) + 1;
972 QRect bounds = option->rect;
973 switch (option->decorationPosition) {
974 case QStyleOptionViewItem::Left:
975 case QStyleOptionViewItem::Right: {
976 if (wrapText && bounds.isValid()) {
977 int width = bounds.width() - 2 * textMargin;
978 if (option->features & QStyleOptionViewItem::HasDecoration)
979 width -= option->decorationSize.width() + 2 * textMargin;
980 bounds.setWidth(width);
981 } else
982 bounds.setWidth(QFIXED_MAX);
983 break;
984 }
985 case QStyleOptionViewItem::Top:
986 case QStyleOptionViewItem::Bottom:
987 if (wrapText)
988 bounds.setWidth(bounds.isValid() ? bounds.width() - 2 * textMargin : option->decorationSize.width());
989 else
990 bounds.setWidth(QFIXED_MAX);
991 break;
992 default:
993 break;
994 }
995
996 if (wrapText && option->features & QStyleOptionViewItem::HasCheckIndicator)
997 bounds.setWidth(bounds.width() - proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth) - 2 * textMargin);
998
999 const int lineWidth = bounds.width();
1000 const QSizeF size = viewItemTextLayout(textLayout, lineWidth);
1001 return QSize(qCeil(size.width()) + 2 * textMargin, qCeil(size.height()));
1002 }
1003 break;
1004 case Qt::DecorationRole:
1005 if (option->features & QStyleOptionViewItem::HasDecoration) {
1006 return option->decorationSize;
1007 }
1008 break;
1009 default:
1010 break;
1011 }
1012
1013 return QSize(0, 0);
1014}
1015
1016void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewItem *option, const QRect &rect) const
1017{
1018 const QWidget *widget = option->widget;
1019 const int textMargin = proxyStyle->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1;
1020
1021 QRect textRect = rect.adjusted(textMargin, 0, -textMargin, 0); // remove width padding
1022 const bool wrapText = option->features & QStyleOptionViewItem::WrapText;
1023 QTextOption textOption;
1024 textOption.setWrapMode(wrapText ? QTextOption::WordWrap : QTextOption::ManualWrap);
1025 textOption.setTextDirection(option->direction);
1026 textOption.setAlignment(QStyle::visualAlignment(option->direction, option->displayAlignment));
1027
1028 QPointF paintPosition;
1029 const QString newText = calculateElidedText(option->text, textOption,
1030 option->font, textRect, option->displayAlignment,
1031 option->textElideMode, 0,
1032 true, &paintPosition);
1033
1034 QTextLayout textLayout(newText, option->font);
1035 textLayout.setTextOption(textOption);
1036 viewItemTextLayout(textLayout, textRect.width());
1037 textLayout.draw(p, paintPosition);
1038}
1039
1040/*! \internal
1041 compute the position for the different component of an item (pixmap, text, checkbox)
1042
1043 Set sizehint to false to layout the elements inside opt->rect. Set sizehint to true to ignore
1044 opt->rect and return rectangles in infinite space
1045
1046 Code duplicated in QItemDelegate::doLayout
1047*/
1048void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItem *opt, QRect *checkRect,
1049 QRect *pixmapRect, QRect *textRect, bool sizehint) const
1050{
1051 Q_ASSERT(checkRect && pixmapRect && textRect);
1052 *pixmapRect = QRect(QPoint(0, 0), viewItemSize(opt, Qt::DecorationRole));
1053 *textRect = QRect(QPoint(0, 0), viewItemSize(opt, Qt::DisplayRole));
1054 *checkRect = QRect(QPoint(0, 0), viewItemSize(opt, Qt::CheckStateRole));
1055
1056 const QWidget *widget = opt->widget;
1057 const bool hasCheck = checkRect->isValid();
1058 const bool hasPixmap = pixmapRect->isValid();
1059 const bool hasText = textRect->isValid();
1060 const bool hasMargin = (hasText | hasPixmap | hasCheck);
1061 const int frameHMargin = hasMargin ?
1062 proxyStyle->pixelMetric(QStyle::PM_FocusFrameHMargin, opt, widget) + 1 : 0;
1063 const int textMargin = hasText ? frameHMargin : 0;
1064 const int pixmapMargin = hasPixmap ? frameHMargin : 0;
1065 const int checkMargin = hasCheck ? frameHMargin : 0;
1066 const int x = opt->rect.left();
1067 const int y = opt->rect.top();
1068 int w, h;
1069
1070 if (textRect->height() == 0 && (!hasPixmap || !sizehint)) {
1071 //if there is no text, we still want to have a decent height for the item sizeHint and the editor size
1072 textRect->setHeight(opt->fontMetrics.height());
1073 }
1074
1075 QSize pm(0, 0);
1076 if (hasPixmap) {
1077 pm = pixmapRect->size();
1078 pm.rwidth() += 2 * pixmapMargin;
1079 }
1080 if (sizehint) {
1081 h = qMax(checkRect->height(), qMax(textRect->height(), pm.height()));
1082 if (opt->decorationPosition == QStyleOptionViewItem::Left
1083 || opt->decorationPosition == QStyleOptionViewItem::Right) {
1084 w = textRect->width() + pm.width();
1085 } else {
1086 w = qMax(textRect->width(), pm.width());
1087 }
1088 } else {
1089 w = opt->rect.width();
1090 h = opt->rect.height();
1091 }
1092
1093 int cw = 0;
1094 QRect check;
1095 if (hasCheck) {
1096 cw = checkRect->width() + 2 * checkMargin;
1097 if (sizehint) w += cw;
1098 if (opt->direction == Qt::RightToLeft) {
1099 check.setRect(x + w - cw, y, cw, h);
1100 } else {
1101 check.setRect(x, y, cw, h);
1102 }
1103 }
1104
1105 QRect display;
1106 QRect decoration;
1107 switch (opt->decorationPosition) {
1108 case QStyleOptionViewItem::Top: {
1109 if (hasPixmap)
1110 pm.setHeight(pm.height() + pixmapMargin); // add space
1111 h = sizehint ? textRect->height() : h - pm.height();
1112
1113 if (opt->direction == Qt::RightToLeft) {
1114 decoration.setRect(x, y, w - cw, pm.height());
1115 display.setRect(x, y + pm.height(), w - cw, h);
1116 } else {
1117 decoration.setRect(x + cw, y, w - cw, pm.height());
1118 display.setRect(x + cw, y + pm.height(), w - cw, h);
1119 }
1120 break; }
1121 case QStyleOptionViewItem::Bottom: {
1122 if (hasText)
1123 textRect->setHeight(textRect->height() + textMargin); // add space
1124 h = sizehint ? textRect->height() + pm.height() : h;
1125
1126 if (opt->direction == Qt::RightToLeft) {
1127 display.setRect(x, y, w - cw, textRect->height());
1128 decoration.setRect(x, y + textRect->height(), w - cw, h - textRect->height());
1129 } else {
1130 display.setRect(x + cw, y, w - cw, textRect->height());
1131 decoration.setRect(x + cw, y + textRect->height(), w - cw, h - textRect->height());
1132 }
1133 break; }
1134 case QStyleOptionViewItem::Left: {
1135 if (opt->direction == Qt::LeftToRight) {
1136 decoration.setRect(x + cw, y, pm.width(), h);
1137 display.setRect(decoration.right() + 1, y, w - pm.width() - cw, h);
1138 } else {
1139 display.setRect(x, y, w - pm.width() - cw, h);
1140 decoration.setRect(display.right() + 1, y, pm.width(), h);
1141 }
1142 break; }
1143 case QStyleOptionViewItem::Right: {
1144 if (opt->direction == Qt::LeftToRight) {
1145 display.setRect(x + cw, y, w - pm.width() - cw, h);
1146 decoration.setRect(display.right() + 1, y, pm.width(), h);
1147 } else {
1148 decoration.setRect(x, y, pm.width(), h);
1149 display.setRect(decoration.right() + 1, y, w - pm.width() - cw, h);
1150 }
1151 break; }
1152 default:
1153 qWarning("doLayout: decoration position is invalid");
1154 decoration = *pixmapRect;
1155 break;
1156 }
1157
1158 if (!sizehint) { // we only need to do the internal layout if we are going to paint
1159 *checkRect = QStyle::alignedRect(opt->direction, Qt::AlignCenter,
1160 checkRect->size(), check);
1161 *pixmapRect = QStyle::alignedRect(opt->direction, opt->decorationAlignment,
1162 pixmapRect->size(), decoration);
1163 // the text takes up all available space, unless the decoration is not shown as selected
1164 if (opt->showDecorationSelected)
1165 *textRect = display;
1166 else
1167 *textRect = QStyle::alignedRect(opt->direction, opt->displayAlignment,
1168 textRect->size().boundedTo(display.size()), display);
1169 } else {
1170 *checkRect = check;
1171 *pixmapRect = decoration;
1172 *textRect = display;
1173 }
1174}
1175#endif // QT_CONFIG(itemviews)
1176
1177#if QT_CONFIG(toolbutton)
1178QString QCommonStylePrivate::toolButtonElideText(const QStyleOptionToolButton *option,
1179 const QRect &textRect, int flags) const
1180{
1181 if (option->fontMetrics.horizontalAdvance(option->text) <= textRect.width())
1182 return option->text;
1183
1184 QString text = option->text;
1185 text.replace('\n', QChar::LineSeparator);
1186 QTextOption textOption;
1187 textOption.setWrapMode(QTextOption::ManualWrap);
1188 textOption.setTextDirection(option->direction);
1189
1190 return calculateElidedText(text, textOption,
1191 option->font, textRect, Qt::AlignTop,
1192 Qt::ElideMiddle, flags,
1193 false, nullptr);
1194}
1195#endif // QT_CONFIG(toolbutton)
1196
1197#if QT_CONFIG(tabbar)
1198/*! \internal
1199 Compute the textRect and the pixmapRect from the opt rect
1200
1201 Uses the same computation than in QTabBar::tabSizeHint
1202 */
1203void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *iconRect) const
1204{
1205 Q_ASSERT(textRect);
1206 Q_ASSERT(iconRect);
1207 QRect tr = opt->rect;
1208 bool verticalTabs = opt->shape == QTabBar::RoundedEast
1209 || opt->shape == QTabBar::RoundedWest
1210 || opt->shape == QTabBar::TriangularEast
1211 || opt->shape == QTabBar::TriangularWest;
1212 if (verticalTabs)
1213 tr.setRect(0, 0, tr.height(), tr.width()); // 0, 0 as we will have a translate transform
1214
1215 int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt, widget);
1216 int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt, widget);
1217 int hpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt, widget) / 2;
1218 int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt, widget) / 2;
1219 if (opt->shape == QTabBar::RoundedSouth || opt->shape == QTabBar::TriangularSouth)
1220 verticalShift = -verticalShift;
1221 tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
1222 bool selected = opt->state & QStyle::State_Selected;
1223 if (selected) {
1224 tr.setTop(tr.top() - verticalShift);
1225 tr.setRight(tr.right() - horizontalShift);
1226 }
1227
1228 // left widget
1229 if (!opt->leftButtonSize.isEmpty()) {
1230 tr.setLeft(tr.left() + 4 +
1231 (verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width()));
1232 }
1233 // right widget
1234 if (!opt->rightButtonSize.isEmpty()) {
1235 tr.setRight(tr.right() - 4 -
1236 (verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width()));
1237 }
1238
1239 // icon
1240 if (!opt->icon.isNull()) {
1241 QSize iconSize = opt->iconSize;
1242 if (!iconSize.isValid()) {
1243 int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize);
1244 iconSize = QSize(iconExtent, iconExtent);
1245 }
1246 QSize tabIconSize = opt->icon.actualSize(iconSize,
1247 (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
1248 (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
1249 // High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize
1250 tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
1251
1252 const int offsetX = (iconSize.width() - tabIconSize.width()) / 2;
1253 *iconRect = QRect(tr.left() + offsetX, tr.center().y() - tabIconSize.height() / 2,
1254 tabIconSize.width(), tabIconSize.height());
1255 if (!verticalTabs)
1256 *iconRect = QStyle::visualRect(opt->direction, opt->rect, *iconRect);
1257 tr.setLeft(tr.left() + tabIconSize.width() + 4);
1258 }
1259
1260 if (!verticalTabs)
1261 tr = QStyle::visualRect(opt->direction, opt->rect, tr);
1262
1263 *textRect = tr;
1264}
1265#endif // QT_CONFIG(tabbar)
1266
1267#if QT_CONFIG(animation)
1268/*! \internal */
1269QList<const QObject*> QCommonStylePrivate::animationTargets() const
1270{
1271 return animations.keys();
1272}
1273
1274/*! \internal */
1275QStyleAnimation * QCommonStylePrivate::animation(const QObject *target) const
1276{
1277 return animations.value(target);
1278}
1279
1280/*! \internal */
1281void QCommonStylePrivate::startAnimation(QStyleAnimation *animation) const
1282{
1283 Q_Q(const QCommonStyle);
1284 stopAnimation(animation->target());
1285 q->connect(animation, SIGNAL(destroyed()), SLOT(_q_removeAnimation()), Qt::UniqueConnection);
1286 animations.insert(animation->target(), animation);
1287 animation->start();
1288}
1289
1290/*! \internal */
1291void QCommonStylePrivate::stopAnimation(const QObject *target) const
1292{
1293 QStyleAnimation *animation = animations.take(target);
1294 if (animation) {
1295 animation->stop();
1296 delete animation;
1297 }
1298}
1299
1300/*! \internal */
1301void QCommonStylePrivate::_q_removeAnimation()
1302{
1303 Q_Q(QCommonStyle);
1304 QObject *animation = q->sender();
1305 if (animation)
1306 animations.remove(animation->parent());
1307}
1308#endif
1309
1310/*!
1311 \reimp
1312*/
1313void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
1314 QPainter *p, const QWidget *widget) const
1315{
1316 Q_D(const QCommonStyle);
1317 switch (element) {
1318
1319 case CE_PushButton:
1320 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1321 proxy()->drawControl(CE_PushButtonBevel, btn, p, widget);
1322 QStyleOptionButton subopt = *btn;
1323 subopt.rect = subElementRect(SE_PushButtonContents, btn, widget);
1324 proxy()->drawControl(CE_PushButtonLabel, &subopt, p, widget);
1325 if (btn->state & State_HasFocus) {
1326 QStyleOptionFocusRect fropt;
1327 fropt.QStyleOption::operator=(*btn);
1328 fropt.rect = subElementRect(SE_PushButtonFocusRect, btn, widget);
1329 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p, widget);
1330 }
1331 }
1332 break;
1333 case CE_PushButtonBevel:
1334 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1335 QRect br = btn->rect;
1336 int dbi = proxy()->pixelMetric(PM_ButtonDefaultIndicator, btn, widget);
1337 if (btn->features & QStyleOptionButton::DefaultButton)
1338 proxy()->drawPrimitive(PE_FrameDefaultButton, opt, p, widget);
1339 if (btn->features & QStyleOptionButton::AutoDefaultButton)
1340 br.setCoords(br.left() + dbi, br.top() + dbi, br.right() - dbi, br.bottom() - dbi);
1341 if (!(btn->features & (QStyleOptionButton::Flat | QStyleOptionButton::CommandLinkButton))
1342 || btn->state & (State_Sunken | State_On)
1343 || (btn->features & QStyleOptionButton::CommandLinkButton && btn->state & State_MouseOver)) {
1344 QStyleOptionButton tmpBtn = *btn;
1345 tmpBtn.rect = br;
1346 proxy()->drawPrimitive(PE_PanelButtonCommand, &tmpBtn, p, widget);
1347 }
1348 if (btn->features & QStyleOptionButton::HasMenu) {
1349 int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, btn, widget);
1350 QRect ir = btn->rect;
1351 QStyleOptionButton newBtn = *btn;
1352 newBtn.rect = QRect(ir.right() - mbi + 2, ir.height()/2 - mbi/2 + 3, mbi - 6, mbi - 6);
1353 proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, p, widget);
1354 }
1355 }
1356 break;
1357 case CE_PushButtonLabel:
1358 if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1359 QRect textRect = button->rect;
1360 uint tf = Qt::AlignVCenter | Qt::TextShowMnemonic;
1361 if (!proxy()->styleHint(SH_UnderlineShortcut, button, widget))
1362 tf |= Qt::TextHideMnemonic;
1363
1364 if (!button->icon.isNull()) {
1365 //Center both icon and text
1366 QRect iconRect;
1367 QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
1368 if (mode == QIcon::Normal && button->state & State_HasFocus)
1369 mode = QIcon::Active;
1370 QIcon::State state = QIcon::Off;
1371 if (button->state & State_On)
1372 state = QIcon::On;
1373
1374 QPixmap pixmap = button->icon.pixmap(qt_getWindow(widget), button->iconSize, mode, state);
1375
1376 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
1377 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
1378 int labelWidth = pixmapWidth;
1379 int labelHeight = pixmapHeight;
1380 int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
1381 int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width();
1382 if (!button->text.isEmpty())
1383 labelWidth += (textWidth + iconSpacing);
1384
1385 iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
1386 textRect.y() + (textRect.height() - labelHeight) / 2,
1387 pixmapWidth, pixmapHeight);
1388
1389 iconRect = visualRect(button->direction, textRect, iconRect);
1390
1391 tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead
1392
1393 if (button->direction == Qt::RightToLeft)
1394 textRect.setRight(iconRect.left() - iconSpacing);
1395 else
1396 textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing);
1397
1398 if (button->state & (State_On | State_Sunken))
1399 iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget),
1400 proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget));
1401 p->drawPixmap(iconRect, pixmap);
1402 } else {
1403 tf |= Qt::AlignHCenter;
1404 }
1405 if (button->state & (State_On | State_Sunken))
1406 textRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget),
1407 proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget));
1408
1409 if (button->features & QStyleOptionButton::HasMenu) {
1410 int indicatorSize = proxy()->pixelMetric(PM_MenuButtonIndicator, button, widget);
1411 if (button->direction == Qt::LeftToRight)
1412 textRect = textRect.adjusted(0, 0, -indicatorSize, 0);
1413 else
1414 textRect = textRect.adjusted(indicatorSize, 0, 0, 0);
1415 }
1416 proxy()->drawItemText(p, textRect, tf, button->palette, (button->state & State_Enabled),
1417 button->text, QPalette::ButtonText);
1418 }
1419 break;
1420 case CE_RadioButton:
1421 case CE_CheckBox:
1422 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1423 bool isRadio = (element == CE_RadioButton);
1424 QStyleOptionButton subopt = *btn;
1425 subopt.rect = subElementRect(isRadio ? SE_RadioButtonIndicator
1426 : SE_CheckBoxIndicator, btn, widget);
1427 proxy()->drawPrimitive(isRadio ? PE_IndicatorRadioButton : PE_IndicatorCheckBox,
1428 &subopt, p, widget);
1429 subopt.rect = subElementRect(isRadio ? SE_RadioButtonContents
1430 : SE_CheckBoxContents, btn, widget);
1431 proxy()->drawControl(isRadio ? CE_RadioButtonLabel : CE_CheckBoxLabel, &subopt, p, widget);
1432 if (btn->state & State_HasFocus) {
1433 QStyleOptionFocusRect fropt;
1434 fropt.QStyleOption::operator=(*btn);
1435 fropt.rect = subElementRect(isRadio ? SE_RadioButtonFocusRect
1436 : SE_CheckBoxFocusRect, btn, widget);
1437 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p, widget);
1438 }
1439 }
1440 break;
1441 case CE_RadioButtonLabel:
1442 case CE_CheckBoxLabel:
1443 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1444 uint alignment = visualAlignment(btn->direction, Qt::AlignLeft | Qt::AlignVCenter);
1445
1446 if (!proxy()->styleHint(SH_UnderlineShortcut, btn, widget))
1447 alignment |= Qt::TextHideMnemonic;
1448 QPixmap pix;
1449 QRect textRect = btn->rect;
1450 if (!btn->icon.isNull()) {
1451 pix = btn->icon.pixmap(qt_getWindow(widget), btn->iconSize, btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled);
1452 proxy()->drawItemPixmap(p, btn->rect, alignment, pix);
1453 if (btn->direction == Qt::RightToLeft)
1454 textRect.setRight(textRect.right() - btn->iconSize.width() - 4);
1455 else
1456 textRect.setLeft(textRect.left() + btn->iconSize.width() + 4);
1457 }
1458 if (!btn->text.isEmpty()){
1459 proxy()->drawItemText(p, textRect, alignment | Qt::TextShowMnemonic,
1460 btn->palette, btn->state & State_Enabled, btn->text, QPalette::WindowText);
1461 }
1462 }
1463 break;
1464#if QT_CONFIG(menu)
1465 case CE_MenuScroller: {
1466 QStyleOption arrowOpt = *opt;
1467 arrowOpt.state |= State_Enabled;
1468 proxy()->drawPrimitive(((opt->state & State_DownArrow) ? PE_IndicatorArrowDown : PE_IndicatorArrowUp),
1469 &arrowOpt, p, widget);
1470 break; }
1471 case CE_MenuTearoff:
1472 if (opt->state & State_Selected)
1473 p->fillRect(opt->rect, opt->palette.brush(QPalette::Highlight));
1474 else
1475 p->fillRect(opt->rect, opt->palette.brush(QPalette::Button));
1476 p->setPen(QPen(opt->palette.dark().color(), 1, Qt::DashLine));
1477 p->drawLine(opt->rect.x() + 2, opt->rect.y() + opt->rect.height() / 2 - 1,
1478 opt->rect.x() + opt->rect.width() - 4,
1479 opt->rect.y() + opt->rect.height() / 2 - 1);
1480 p->setPen(QPen(opt->palette.light().color(), 1, Qt::DashLine));
1481 p->drawLine(opt->rect.x() + 2, opt->rect.y() + opt->rect.height() / 2,
1482 opt->rect.x() + opt->rect.width() - 4, opt->rect.y() + opt->rect.height() / 2);
1483 break;
1484#endif // QT_CONFIG(menu)
1485#if QT_CONFIG(menubar)
1486 case CE_MenuBarItem:
1487 if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
1488 uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip
1489 | Qt::TextSingleLine;
1490 if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
1491 alignment |= Qt::TextHideMnemonic;
1492 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
1493 QPixmap pix = mbi->icon.pixmap(qt_getWindow(widget), QSize(iconExtent, iconExtent), (mbi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled);
1494 if (!pix.isNull())
1495 proxy()->drawItemPixmap(p,mbi->rect, alignment, pix);
1496 else
1497 proxy()->drawItemText(p, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled,
1498 mbi->text, QPalette::ButtonText);
1499 }
1500 break;
1501 case CE_MenuBarEmptyArea:
1502 if (widget && !widget->testAttribute(Qt::WA_NoSystemBackground))
1503 p->eraseRect(opt->rect);
1504 break;
1505#endif // QT_CONFIG(menubar)
1506#if QT_CONFIG(progressbar)
1507 case CE_ProgressBar:
1508 if (const QStyleOptionProgressBar *pb
1509 = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
1510 QStyleOptionProgressBar subopt = *pb;
1511 subopt.rect = subElementRect(SE_ProgressBarGroove, pb, widget);
1512 proxy()->drawControl(CE_ProgressBarGroove, &subopt, p, widget);
1513 subopt.rect = subElementRect(SE_ProgressBarContents, pb, widget);
1514 proxy()->drawControl(CE_ProgressBarContents, &subopt, p, widget);
1515 if (pb->textVisible) {
1516 subopt.rect = subElementRect(SE_ProgressBarLabel, pb, widget);
1517 proxy()->drawControl(CE_ProgressBarLabel, &subopt, p, widget);
1518 }
1519 }
1520 break;
1521 case CE_ProgressBarGroove:
1522 if (opt->rect.isValid())
1523 qDrawShadePanel(p, opt->rect, opt->palette, true, 1,
1524 &opt->palette.brush(QPalette::Window));
1525 break;
1526 case CE_ProgressBarLabel:
1527 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
1528 const bool vertical = pb->orientation == Qt::Vertical;
1529 if (!vertical) {
1530 QPalette::ColorRole textRole = QPalette::NoRole;
1531 if ((pb->textAlignment & Qt::AlignCenter) && pb->textVisible
1532 && ((qint64(pb->progress) - qint64(pb->minimum)) * 2 >= (qint64(pb->maximum) - qint64(pb->minimum)))) {
1533 textRole = QPalette::HighlightedText;
1534 //Draw text shadow, This will increase readability when the background of same color
1535 QRect shadowRect(pb->rect);
1536 shadowRect.translate(1,1);
1537 QColor shadowColor = (pb->palette.color(textRole).value() <= 128)
1538 ? QColor(255,255,255,160) : QColor(0,0,0,160);
1539 QPalette shadowPalette = pb->palette;
1540 shadowPalette.setColor(textRole, shadowColor);
1541 proxy()->drawItemText(p, shadowRect, Qt::AlignCenter | Qt::TextSingleLine, shadowPalette,
1542 pb->state & State_Enabled, pb->text, textRole);
1543 }
1544 proxy()->drawItemText(p, pb->rect, Qt::AlignCenter | Qt::TextSingleLine, pb->palette,
1545 pb->state & State_Enabled, pb->text, textRole);
1546 }
1547 }
1548 break;
1549 case CE_ProgressBarContents:
1550 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
1551
1552 QRect rect = pb->rect;
1553 const bool vertical = pb->orientation == Qt::Vertical;
1554 const bool inverted = pb->invertedAppearance;
1555 qint64 minimum = qint64(pb->minimum);
1556 qint64 maximum = qint64(pb->maximum);
1557 qint64 progress = qint64(pb->progress);
1558
1559 QMatrix m;
1560
1561 if (vertical) {
1562 rect = QRect(rect.y(), rect.x(), rect.height(), rect.width()); // flip width and height
1563 m.rotate(90);
1564 m.translate(0, -(rect.height() + rect.y()*2));
1565 }
1566
1567 QPalette pal2 = pb->palette;
1568 // Correct the highlight color if it is the same as the background
1569 if (pal2.highlight() == pal2.window())
1570 pal2.setColor(QPalette::Highlight, pb->palette.color(QPalette::Active,
1571 QPalette::Highlight));
1572 bool reverse = ((!vertical && (pb->direction == Qt::RightToLeft)) || vertical);
1573 if (inverted)
1574 reverse = !reverse;
1575 int w = rect.width();
1576 if (pb->minimum == 0 && pb->maximum == 0) {
1577 // draw busy indicator
1578 int x = (progress - minimum) % (w * 2);
1579 if (x > w)
1580 x = 2 * w - x;
1581 x = reverse ? rect.right() - x : x + rect.x();
1582 p->setPen(QPen(pal2.highlight().color(), 4));
1583 p->drawLine(x, rect.y(), x, rect.height());
1584 } else {
1585 const int unit_width = proxy()->pixelMetric(PM_ProgressBarChunkWidth, pb, widget);
1586 if (!unit_width)
1587 return;
1588
1589 int u;
1590 if (unit_width > 1)
1591 u = ((rect.width() + unit_width) / unit_width);
1592 else
1593 u = w / unit_width;
1594 qint64 p_v = progress - minimum;
1595 qint64 t_s = (maximum - minimum) ? (maximum - minimum) : qint64(1);
1596
1597 if (u > 0 && p_v >= INT_MAX / u && t_s >= u) {
1598 // scale down to something usable.
1599 p_v /= u;
1600 t_s /= u;
1601 }
1602
1603 // nu < tnu, if last chunk is only a partial chunk
1604 int tnu, nu;
1605 tnu = nu = p_v * u / t_s;
1606
1607 if (nu * unit_width > w)
1608 --nu;
1609
1610 // Draw nu units out of a possible u of unit_width
1611 // width, each a rectangle bordered by background
1612 // color, all in a sunken panel with a percentage text
1613 // display at the end.
1614 int x = 0;
1615 int x0 = reverse ? rect.right() - ((unit_width > 1) ? unit_width : 0)
1616 : rect.x();
1617
1618 QStyleOptionProgressBar pbBits = *pb;
1619 pbBits.rect = rect;
1620 pbBits.palette = pal2;
1621 int myY = pbBits.rect.y();
1622 int myHeight = pbBits.rect.height();
1623 pbBits.state = State_None;
1624 for (int i = 0; i < nu; ++i) {
1625 pbBits.rect.setRect(x0 + x, myY, unit_width, myHeight);
1626 pbBits.rect = m.mapRect(QRectF(pbBits.rect)).toRect();
1627 proxy()->drawPrimitive(PE_IndicatorProgressChunk, &pbBits, p, widget);
1628 x += reverse ? -unit_width : unit_width;
1629 }
1630
1631 // Draw the last partial chunk to fill up the
1632 // progress bar entirely
1633 if (nu < tnu) {
1634 int pixels_left = w - (nu * unit_width);
1635 int offset = reverse ? x0 + x + unit_width-pixels_left : x0 + x;
1636 pbBits.rect.setRect(offset, myY, pixels_left, myHeight);
1637 pbBits.rect = m.mapRect(QRectF(pbBits.rect)).toRect();
1638 proxy()->drawPrimitive(PE_IndicatorProgressChunk, &pbBits, p, widget);
1639 }
1640 }
1641 }
1642 break;
1643#endif // QT_CONFIG(progressbar)
1644 case CE_HeaderLabel:
1645 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
1646 QRect rect = header->rect;
1647 if (!header->icon.isNull()) {
1648 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
1649 QPixmap pixmap
1650 = header->icon.pixmap(qt_getWindow(widget), QSize(iconExtent, iconExtent), (header->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled);
1651 int pixw = pixmap.width() / pixmap.devicePixelRatio();
1652
1653 QRect aligned = alignedRect(header->direction, QFlag(header->iconAlignment), pixmap.size() / pixmap.devicePixelRatio(), rect);
1654 QRect inter = aligned.intersected(rect);
1655 p->drawPixmap(inter.x(), inter.y(), pixmap,
1656 inter.x() - aligned.x(), inter.y() - aligned.y(),
1657 aligned.width() * pixmap.devicePixelRatio(),
1658 pixmap.height() * pixmap.devicePixelRatio());
1659
1660 const int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget);
1661 if (header->direction == Qt::LeftToRight)
1662 rect.setLeft(rect.left() + pixw + margin);
1663 else
1664 rect.setRight(rect.right() - pixw - margin);
1665 }
1666 if (header->state & QStyle::State_On) {
1667 QFont fnt = p->font();
1668 fnt.setBold(true);
1669 p->setFont(fnt);
1670 }
1671 proxy()->drawItemText(p, rect, header->textAlignment, header->palette,
1672 (header->state & State_Enabled), header->text, QPalette::ButtonText);
1673 }
1674 break;
1675#if QT_CONFIG(toolbutton)
1676 case CE_ToolButtonLabel:
1677 if (const QStyleOptionToolButton *toolbutton
1678 = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
1679 QRect rect = toolbutton->rect;
1680 int shiftX = 0;
1681 int shiftY = 0;
1682 if (toolbutton->state & (State_Sunken | State_On)) {
1683 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
1684 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
1685 }
1686 // Arrow type always overrules and is always shown
1687 bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
1688 if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
1689 || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
1690 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1691 if (!proxy()->styleHint(SH_UnderlineShortcut, opt, widget))
1692 alignment |= Qt::TextHideMnemonic;
1693 rect.translate(shiftX, shiftY);
1694 p->setFont(toolbutton->font);
1695 proxy()->drawItemText(p, rect, alignment, toolbutton->palette,
1696 opt->state & State_Enabled, toolbutton->text,
1697 QPalette::ButtonText);
1698 } else {
1699 QPixmap pm;
1700 QSize pmSize = toolbutton->iconSize;
1701 if (!toolbutton->icon.isNull()) {
1702 QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
1703 QIcon::Mode mode;
1704 if (!(toolbutton->state & State_Enabled))
1705 mode = QIcon::Disabled;
1706 else if ((opt->state & State_MouseOver) && (opt->state & State_AutoRaise))
1707 mode = QIcon::Active;
1708 else
1709 mode = QIcon::Normal;
1710 pm = toolbutton->icon.pixmap(qt_getWindow(widget), toolbutton->rect.size().boundedTo(toolbutton->iconSize),
1711 mode, state);
1712 pmSize = pm.size() / pm.devicePixelRatio();
1713 }
1714
1715 if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
1716 p->setFont(toolbutton->font);
1717 QRect pr = rect,
1718 tr = rect;
1719 int alignment = Qt::TextShowMnemonic;
1720 if (!proxy()->styleHint(SH_UnderlineShortcut, opt, widget))
1721 alignment |= Qt::TextHideMnemonic;
1722
1723 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
1724 pr.setHeight(pmSize.height() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
1725 tr.adjust(0, pr.height() - 1, 0, -1);
1726 pr.translate(shiftX, shiftY);
1727 if (!hasArrow) {
1728 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pm);
1729 } else {
1730 drawArrow(proxy(), toolbutton, pr, p, widget);
1731 }
1732 alignment |= Qt::AlignCenter;
1733 } else {
1734 pr.setWidth(pmSize.width() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
1735 tr.adjust(pr.width(), 0, 0, 0);
1736 pr.translate(shiftX, shiftY);
1737 if (!hasArrow) {
1738 proxy()->drawItemPixmap(p, QStyle::visualRect(opt->direction, rect, pr), Qt::AlignCenter, pm);
1739 } else {
1740 drawArrow(proxy(), toolbutton, pr, p, widget);
1741 }
1742 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
1743 }
1744 tr.translate(shiftX, shiftY);
1745 const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
1746 proxy()->drawItemText(p, QStyle::visualRect(opt->direction, rect, tr), alignment, toolbutton->palette,
1747 toolbutton->state & State_Enabled, text,
1748 QPalette::ButtonText);
1749 } else {
1750 rect.translate(shiftX, shiftY);
1751 if (hasArrow) {
1752 drawArrow(proxy(), toolbutton, rect, p, widget);
1753 } else {
1754 proxy()->drawItemPixmap(p, rect, Qt::AlignCenter, pm);
1755 }
1756 }
1757 }
1758 }
1759 break;
1760#endif // QT_CONFIG(toolbutton)
1761#if QT_CONFIG(toolbox)
1762 case CE_ToolBoxTab:
1763 if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
1764 proxy()->drawControl(CE_ToolBoxTabShape, tb, p, widget);
1765 proxy()->drawControl(CE_ToolBoxTabLabel, tb, p, widget);
1766 }
1767 break;
1768 case CE_ToolBoxTabShape:
1769 if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
1770 p->setPen(tb->palette.mid().color().darker(150));
1771 bool oldQt4CompatiblePainting = p->testRenderHint(QPainter::Qt4CompatiblePainting);
1772 p->setRenderHint(QPainter::Qt4CompatiblePainting);
1773 int d = 20 + tb->rect.height() - 3;
1774 if (tb->direction != Qt::RightToLeft) {
1775 const QPoint points[] = {
1776 QPoint(-1, tb->rect.height() + 1),
1777 QPoint(-1, 1),
1778 QPoint(tb->rect.width() - d, 1),
1779 QPoint(tb->rect.width() - 20, tb->rect.height() - 2),
1780 QPoint(tb->rect.width() - 1, tb->rect.height() - 2),
1781 QPoint(tb->rect.width() - 1, tb->rect.height() + 1),
1782 QPoint(-1, tb->rect.height() + 1),
1783 };
1784 p->drawPolygon(points, sizeof points / sizeof *points);
1785 } else {
1786 const QPoint points[] = {
1787 QPoint(tb->rect.width(), tb->rect.height() + 1),
1788 QPoint(tb->rect.width(), 1),
1789 QPoint(d - 1, 1),
1790 QPoint(20 - 1, tb->rect.height() - 2),
1791 QPoint(0, tb->rect.height() - 2),
1792 QPoint(0, tb->rect.height() + 1),
1793 QPoint(tb->rect.width(), tb->rect.height() + 1),
1794 };
1795 p->drawPolygon(points, sizeof points / sizeof *points);