1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Qt Software Information (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at qt-sales@nokia.com.
27 **
28 **************************************************************************/
29 #include "manhattanstyle.h"
30
31 #include "stylehelper.h"
32 #include "styleanimator.h"
33
34 #include <QtCore/QDebug>
35 #include <QtCore/QLibrary>
36
37 #include <QApplication>
38 #include <QComboBox>
39 #include <QDialog>
40 #include <QDialogButtonBox>
41 #include <QDockWidget>
42 #include <QLabel>
43 #include <QLineEdit>
44 #include <QMainWindow>
45 #include <QMenuBar>
46 #include <QPainter>
47 #include <QPainterPath>
48 #include <QPixmap>
49 #include <QPixmapCache>
50 #include <QPushButton>
51 #include <QScrollArea>
52 #include <QSplitter>
53 #include <QStatusBar>
54 #include <QStyleFactory>
55 #include <QStyleOption>
56 #include <QToolBar>
57 #include <QToolButton>
58 #include "utilsSystem.h"
59
60
61
62 // We define a currently unused state for indicating animations
63 const unsigned int State_Animating = 0x00000040;
64
65 // Because designer needs to disable this for widget previews
66 // we have a custom property that is inherited
styleEnabled(const QWidget * widget)67 bool styleEnabled(const QWidget *widget)
68 {
69 const QWidget *p = widget;
70 while (p) {
71 if (p->property("_q_custom_style_disabled").toBool())
72 return false;
73 p = p->parentWidget();
74 }
75 return true;
76 }
77
78 // Consider making this a QStyle state
panelWidget(const QWidget * widget)79 bool panelWidget(const QWidget *widget)
80 {
81 const QWidget *p = widget;
82
83 while (p) {
84 if (qobject_cast<const QToolBar *>(p) && styleEnabled(p))
85 return true;
86 else if (qobject_cast<const QStatusBar *>(p) && styleEnabled(p))
87 return true;
88 else if (qobject_cast<const QMenuBar *>(p) && styleEnabled(p))
89 return true;
90 p = p->parentWidget();
91 }
92 return false;
93 }
94
95 class ManhattanStylePrivate
96 {
97 public:
ManhattanStylePrivate(const QString & baseStyleName)98 ManhattanStylePrivate(const QString &baseStyleName)
99 {
100 style = QStyleFactory::create(baseStyleName);
101 // Q_ASSERT(style, "no style");
102 // QTC_ASSERT(style, /**/);
103 buttonImage_pressed = QImage(":/images/pushbutton.png");
104 buttonImage = QImage(":/images/pushbutton.png");
105
106 lineeditImage = QImage(":/images/inputfield.png");
107 lineeditImage_disabled = QImage(":/images/inputfield_disabled.png");
108 }
109
~ManhattanStylePrivate()110 ~ManhattanStylePrivate()
111 {
112 delete style;
113 style = nullptr;
114 }
115
116 void init();
117
118 public:
119 QStyle *style;
120 QImage buttonImage;
121 QImage buttonImage_pressed;
122 QImage lineeditImage;
123 QImage lineeditImage_disabled;
124
125 StyleAnimator animator;
126 };
127
ManhattanStyle(const QString & baseStyleName)128 ManhattanStyle::ManhattanStyle(const QString &baseStyleName)
129 : QProxyStyle(), d(new ManhattanStylePrivate(baseStyleName))
130 {
131 setProperty("manhattanstyle", true);
132 }
133
~ManhattanStyle()134 ManhattanStyle::~ManhattanStyle()
135 {
136 delete d;
137 d = nullptr;
138 }
139
isValid()140 bool ManhattanStyle::isValid()
141 {
142 return d && d->style;
143 }
144
145 // Draws a CSS-like border image where the defined borders are not stretched
drawCornerImage(const QImage & img,QPainter * painter,QRect rect,int left=0,int top=0,int right=0,int bottom=0)146 void drawCornerImage(const QImage &img, QPainter *painter, QRect rect,
147 int left = 0, int top = 0, int right = 0,
148 int bottom = 0)
149 {
150 QSize size = img.size();
151 if (top > 0) { //top
152 painter->drawImage(QRect(rect.left() + left, rect.top(), rect.width() - right - left, top), img,
153 QRect(left, 0, size.width() - right - left, top));
154 if (left > 0) //top-left
155 painter->drawImage(QRect(rect.left(), rect.top(), left, top), img,
156 QRect(0, 0, left, top));
157 if (right > 0) //top-right
158 painter->drawImage(QRect(rect.left() + rect.width() - right, rect.top(), right, top), img,
159 QRect(size.width() - right, 0, right, top));
160 }
161 //left
162 if (left > 0)
163 painter->drawImage(QRect(rect.left(), rect.top() + top, left, rect.height() - top - bottom), img,
164 QRect(0, top, left, size.height() - bottom - top));
165 //center
166 painter->drawImage(QRect(rect.left() + left, rect.top() + top, rect.width() - right - left,
167 rect.height() - bottom - top), img,
168 QRect(left, top, size.width() - right - left,
169 size.height() - bottom - top));
170 if (right > 0) //right
171 painter->drawImage(QRect(rect.left() + rect.width() - right, rect.top() + top, right, rect.height() - top - bottom), img,
172 QRect(size.width() - right, top, right, size.height() - bottom - top));
173 if (bottom > 0) { //bottom
174 painter->drawImage(QRect(rect.left() + left, rect.top() + rect.height() - bottom,
175 rect.width() - right - left, bottom), img,
176 QRect(left, size.height() - bottom,
177 size.width() - right - left, bottom));
178 if (left > 0) //bottom-left
179 painter->drawImage(QRect(rect.left(), rect.top() + rect.height() - bottom, left, bottom), img,
180 QRect(0, size.height() - bottom, left, bottom));
181 if (right > 0) //bottom-right
182 painter->drawImage(QRect(rect.left() + rect.width() - right, rect.top() + rect.height() - bottom, right, bottom), img,
183 QRect(size.width() - right, size.height() - bottom, right, bottom));
184 }
185 }
186
generatedIconPixmap(QIcon::Mode iconMode,const QPixmap & pixmap,const QStyleOption * opt) const187 QPixmap ManhattanStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const
188 {
189 QPixmap result;
190 result = d->style->generatedIconPixmap(iconMode, pixmap, opt);
191 return result;
192 }
193
layoutSpacingImplementation(QSizePolicy::ControlType control1,QSizePolicy::ControlType control2,Qt::Orientation orientation,const QStyleOption * option,const QWidget * widget) const194 int ManhattanStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1,
195 QSizePolicy::ControlType control2,
196 Qt::Orientation orientation,
197 const QStyleOption *option ,
198 const QWidget *widget ) const
199 {
200 return d->style->layoutSpacing(control1, control2, orientation, option, widget);
201
202 }
203
sizeFromContents(ContentsType type,const QStyleOption * option,const QSize & size,const QWidget * widget) const204 QSize ManhattanStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
205 const QSize &size, const QWidget *widget) const
206 {
207 QSize newSize = d->style->sizeFromContents(type, option, size, widget);
208
209 if (type == CT_Splitter && widget && widget->property("minisplitter").toBool())
210 return QSize(1, 1);
211 else if (type == CT_ComboBox && panelWidget(widget))
212 newSize += QSize(1, 0);
213 return newSize;
214 }
215
subElementRect(SubElement element,const QStyleOption * option,const QWidget * widget) const216 QRect ManhattanStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
217 {
218 QRect rect;
219 rect = d->style->subElementRect(element, option, widget);
220 return rect;
221 }
222
subControlRect(ComplexControl control,const QStyleOptionComplex * option,SubControl subControl,const QWidget * widget) const223 QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
224 SubControl subControl, const QWidget *widget) const
225 {
226 QRect rect;
227 rect = d->style->subControlRect(control, option, subControl, widget);
228 return rect;
229 }
230
hitTestComplexControl(ComplexControl control,const QStyleOptionComplex * option,const QPoint & pos,const QWidget * widget) const231 QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
232 const QPoint &pos, const QWidget *widget) const
233 {
234 SubControl result = QStyle::SC_None;
235 result = d->style->hitTestComplexControl(control, option, pos, widget);
236 return result;
237 }
238
pixelMetric(PixelMetric metric,const QStyleOption * option,const QWidget * widget) const239 int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
240 {
241 int retval = 0;
242 retval = d->style->pixelMetric(metric, option, widget);
243 switch (metric) {
244 case PM_SplitterWidth:
245 if (widget && widget->property("minisplitter").toBool())
246 retval = 1;
247 break;
248 case PM_ToolBarIconSize:
249 if (panelWidget(widget))
250 retval = 16;
251 break;
252 case PM_MenuPanelWidth:
253 case PM_MenuBarHMargin:
254 case PM_MenuBarVMargin:
255 case PM_ToolBarFrameWidth:
256 if (panelWidget(widget))
257 retval = 1;
258 break;
259 case PM_ButtonShiftVertical:
260 case PM_ButtonShiftHorizontal:
261 case PM_MenuBarPanelWidth:
262 case PM_ToolBarItemMargin:
263 case PM_ToolBarItemSpacing:
264 if (panelWidget(widget))
265 retval = 0;
266 break;
267 case PM_DefaultFrameWidth:
268 if (qobject_cast<const QLineEdit *>(widget) && panelWidget(widget))
269 return 1;
270 break;
271 default:
272 break;
273 }
274 return retval;
275 }
276
standardPalette() const277 QPalette ManhattanStyle::standardPalette() const
278 {
279 QPalette result;
280 result = d->style->standardPalette();
281 return result;
282 }
283
polish(QApplication * app)284 void ManhattanStyle::polish(QApplication *app)
285 {
286 d->style->polish(app);
287 }
288
unpolish(QApplication * app)289 void ManhattanStyle::unpolish(QApplication *app)
290 {
291 d->style->unpolish(app);
292 }
293
panelPalette(const QPalette & oldPalette)294 QPalette panelPalette(const QPalette &oldPalette)
295 {
296 QColor color = StyleHelper::panelTextColor();
297 QPalette pal = oldPalette;
298 pal.setBrush(QPalette::All, QPalette::WindowText, color);
299 pal.setBrush(QPalette::All, QPalette::ButtonText, color);
300 color.setAlpha(100);
301 pal.setBrush(QPalette::Disabled, QPalette::WindowText, color);
302 pal.setBrush(QPalette::Disabled, QPalette::ButtonText, color);
303 return pal;
304 }
305
polish(QWidget * widget)306 void ManhattanStyle::polish(QWidget *widget)
307 {
308 d->style->polish(widget);
309
310 // OxygenStyle forces a rounded widget mask on toolbars
311 if (d->style->inherits("OxygenStyle")) {
312 if (qobject_cast<QToolBar *>(widget))
313 widget->removeEventFilter(d->style);
314 }
315 if (panelWidget(widget)) {
316 if (qobject_cast<QToolButton *>(widget)) {
317 widget->setAttribute(Qt::WA_Hover);
318 // NOTE: we do not really use the concept of navigation/panel widgets but we have
319 // regular toolbars that would be affected by the height limitation
320 // so we deactivate it
321 // widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2);
322 widget->setAttribute(Qt::WA_Hover);
323 } else if (qobject_cast<QLineEdit *>(widget)) {
324 widget->setAttribute(Qt::WA_Hover);
325 widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2);
326 } else if (qobject_cast<QLabel *>(widget))
327 widget->setPalette(panelPalette(widget->palette()));
328 /* else if (qobject_cast<QToolBar*>(widget))
329 widget->setMinimumHeight(StyleHelper::navigationWidgetHeight());
330 // else if (qobject_cast<QStatusBar*>(widget))
331 // widget->setFixedHeight(StyleHelper::navigationWidgetHeight() + 2);
332 else if (qobject_cast<QComboBox*>(widget)) {
333 widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2);
334 widget->setAttribute(Qt::WA_Hover);
335 }
336 */
337 }
338 }
339
unpolish(QWidget * widget)340 void ManhattanStyle::unpolish(QWidget *widget)
341 {
342 d->style->unpolish(widget);
343 if (panelWidget(widget)) {
344 if (qobject_cast<QTabBar *>(widget))
345 widget->setAttribute(Qt::WA_Hover, false);
346 else if (qobject_cast<QToolBar *>(widget))
347 widget->setAttribute(Qt::WA_Hover, false);
348 else if (qobject_cast<QComboBox *>(widget))
349 widget->setAttribute(Qt::WA_Hover, false);
350 }
351 }
352
polish(QPalette & pal)353 void ManhattanStyle::polish(QPalette &pal)
354 {
355 d->style->polish(pal);
356 }
357
standardIconImplementation(StandardPixmap standardIcon,const QStyleOption * option,const QWidget * widget) const358 QIcon ManhattanStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option,
359 const QWidget *widget) const
360 {
361 QIcon icon;
362 switch (standardIcon) {
363 case QStyle::SP_TitleBarCloseButton:
364 case QStyle::SP_ToolBarHorizontalExtensionButton:
365 return QIcon(standardPixmap(standardIcon, option, widget));
366 default:
367 icon = d->style->standardIcon(standardIcon, option, widget);
368 }
369 return icon;
370 }
371
standardPixmap(StandardPixmap standardPixmap,const QStyleOption * opt,const QWidget * widget) const372 QPixmap ManhattanStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
373 const QWidget *widget) const
374 {
375 if (widget && !panelWidget(widget))
376 return d->style->standardPixmap(standardPixmap, opt, widget);
377
378 QPixmap pixmap;
379 switch (standardPixmap) {
380 /* TH 2012-06-03: commented out -> use standard version
381 case QStyle::SP_ToolBarHorizontalExtensionButton: {
382 static const QPixmap extButton(":/images/extension.png");
383 pixmap = extButton;
384 }
385 break;
386 */
387 case QStyle::SP_TitleBarCloseButton: {
388 static const QPixmap closeButton(":/images/closebutton.png");
389 pixmap = closeButton;
390 }
391 break;
392 default:
393 pixmap = d->style->standardPixmap(standardPixmap, opt, widget);
394 }
395 return pixmap;
396 }
397
398
styleHint(StyleHint hint,const QStyleOption * option,const QWidget * widget,QStyleHintReturn * returnData) const399 int ManhattanStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
400 QStyleHintReturn *returnData) const
401 {
402 int ret = d->style->styleHint(hint, option, widget, returnData);
403 switch (hint) {
404 // Make project explorer alternate rows all the way
405 case QStyle::SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
406 if (widget && widget->property("AlternateEmpty").toBool())
407 ret = true;
408 break;
409 case QStyle::SH_EtchDisabledText:
410 if (panelWidget(widget))
411 ret = false;
412 break;
413 default:
414 break;
415 }
416 return ret;
417 }
418
drawPrimitive(PrimitiveElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const419 void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
420 QPainter *painter, const QWidget *widget) const
421 {
422 if (!panelWidget(widget))
423 return d->style->drawPrimitive(element, option, painter, widget);
424
425 bool animating = (option->state & State_Animating);
426 int state = option->state;
427 QRect rect = option->rect;
428 QRect oldRect;
429 QRect newRect;
430 if (widget && (element == PE_PanelButtonTool) && !animating) {
431 QWidget *w = const_cast<QWidget *> (widget);
432 int oldState = w->property("_q_stylestate").toInt();
433 oldRect = w->property("_q_stylerect").toRect();
434 newRect = w->rect();
435 w->setProperty("_q_stylestate", static_cast<int>(option->state));
436 w->setProperty("_q_stylerect", w->rect());
437
438 // Determine the animated transition
439 bool doTransition = ((state & State_On) != (oldState & State_On) ||
440 (state & State_MouseOver) != (oldState & State_MouseOver));
441 if (oldRect != newRect) {
442 doTransition = false;
443 d->animator.stopAnimation(widget);
444 }
445
446 if (doTransition) {
447 QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
448 QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
449 Animation *anim = d->animator.widgetAnimation(widget);
450 QStyleOption opt = *option;
451 opt.state = static_cast<QStyle::State>(oldState);
452 opt.state |= static_cast<State>(State_Animating);
453 startImage.fill(0);
454 Transition *t = new Transition;
455 t->setWidget(w);
456 QPainter startPainter(&startImage);
457 if (!anim) {
458 drawPrimitive(element, &opt, &startPainter, widget);
459 } else {
460 anim->paint(&startPainter, &opt);
461 d->animator.stopAnimation(widget);
462 }
463 QStyleOption endOpt = *option;
464 endOpt.state |= static_cast<State>(State_Animating);
465 t->setStartImage(startImage);
466 d->animator.startAnimation(t);
467 endImage.fill(0);
468 QPainter endPainter(&endImage);
469 drawPrimitive(element, &endOpt, &endPainter, widget);
470 t->setEndImage(endImage);
471 t->setDuration(130);
472 t->setStartTime(QTime::currentTime());
473 }
474 }
475
476 switch (element) {
477 case PE_PanelLineEdit: {
478 painter->save();
479 if (option->state & State_Enabled)
480 drawCornerImage(d->lineeditImage, painter, option->rect, 2, 2, 2, 2);
481 else
482 drawCornerImage(d->lineeditImage_disabled, painter, option->rect, 2, 2, 2, 2);
483
484 if (option->state & State_HasFocus || option->state & State_MouseOver) {
485 QColor hover = StyleHelper::baseColor();
486 if (state & State_HasFocus)
487 hover.setAlpha(100);
488 else
489 hover.setAlpha(50);
490
491 painter->setPen(QPen(hover, 1));
492 painter->drawRect(option->rect.adjusted(1, 1, -2 , -2));
493 }
494 painter->restore();
495 }
496 break;
497
498 case PE_FrameStatusBarItem:
499 break;
500
501 case PE_PanelButtonTool: {
502 Animation *anim = d->animator.widgetAnimation(widget);
503 if (!animating && anim) {
504 anim->paint(painter, option);
505 } else {
506 bool pressed = option->state & State_Sunken || option->state & State_On;
507 QColor shadow(0, 0, 0, 30);
508 painter->setPen(shadow);
509 if (pressed) {
510 QColor shade(0, 0, 0, 40);
511 painter->fillRect(rect, shade);
512 painter->drawLine(rect.topLeft() + QPoint(1, 0), rect.topRight() - QPoint(1, 0));
513 painter->drawLine(rect.topLeft(), rect.bottomLeft());
514 painter->drawLine(rect.topRight(), rect.bottomRight());
515 // painter->drawLine(rect.bottomLeft() + QPoint(1, 0), rect.bottomRight() - QPoint(1, 0));
516 QColor highlight(255, 255, 255, 30);
517 painter->setPen(highlight);
518 } else if (option->state & State_Enabled &&
519 option->state & State_MouseOver) {
520 QColor lighter(255, 255, 255, 37);
521 painter->fillRect(rect, lighter);
522 }
523 }
524 }
525 break;
526
527 case PE_PanelStatusBar: {
528 painter->save();
529 QLinearGradient grad(option->rect.topLeft(), QPoint(rect.center().x(), rect.bottom()));
530 QColor startColor = StyleHelper::shadowColor().darker(164);
531 QColor endColor = StyleHelper::baseColor().darker(130);
532 grad.setColorAt(0, startColor);
533 grad.setColorAt(1, endColor);
534 painter->fillRect(option->rect, grad);
535 painter->setPen(QColor(255, 255, 255, 60));
536 painter->drawLine(rect.topLeft() + QPoint(0, 1),
537 rect.topRight() + QPoint(0, 1));
538 painter->setPen(StyleHelper::borderColor().darker(110));
539 painter->drawLine(rect.topLeft(), rect.topRight());
540 painter->restore();
541 }
542 break;
543
544 case PE_IndicatorToolBarSeparator: {
545 QColor separatorColor = StyleHelper::borderColor();
546 separatorColor.setAlpha(100);
547 painter->setPen(separatorColor);
548 const int margin = 3;
549 if (option->state & State_Horizontal) {
550 const int offset = rect.width() / 2;
551 painter->drawLine(rect.bottomLeft().x() + offset,
552 rect.bottomLeft().y() - margin,
553 rect.topLeft().x() + offset,
554 rect.topLeft().y() + margin);
555 } else { //Draw vertical separator
556 const int offset = rect.height() / 2;
557 painter->setPen(QPen(option->palette.window().color().darker(110)));
558 painter->drawLine(rect.topLeft().x() + margin ,
559 rect.topLeft().y() + offset,
560 rect.topRight().x() - margin,
561 rect.topRight().y() + offset);
562 }
563 }
564 break;
565
566 case PE_IndicatorToolBarHandle: {
567 bool horizontal = option->state & State_Horizontal;
568 painter->save();
569 QPainterPath path;
570 int x = option->rect.x() + (horizontal ? 2 : 6 );
571 int y = option->rect.y() + (horizontal ? 6 : 2 );
572 static const int RectHeight = 2;
573 if (horizontal) {
574 while (y < option->rect.height() - RectHeight - 6) {
575 path.moveTo(x, y);
576 path.addRect(x, y, RectHeight, RectHeight);
577 y += 6;
578 }
579 } else {
580 while (x < option->rect.width() - RectHeight - 6) {
581 path.moveTo(x, y);
582 path.addRect(x, y, RectHeight, RectHeight);
583 x += 6;
584 }
585 }
586
587 painter->setPen(Qt::NoPen);
588 QColor dark = StyleHelper::borderColor();
589 dark.setAlphaF(0.4);
590
591 QColor light = StyleHelper::baseColor();
592 light.setAlphaF(0.4);
593
594 painter->fillPath(path, light);
595 painter->save();
596 painter->translate(1, 1);
597 painter->fillPath(path, dark);
598 painter->restore();
599 painter->translate(3, 3);
600 painter->fillPath(path, light);
601 painter->translate(1, 1);
602 painter->fillPath(path, dark);
603 painter->restore();
604 }
605 break;
606 case PE_IndicatorArrowUp:
607 case PE_IndicatorArrowDown:
608 case PE_IndicatorArrowRight:
609 case PE_IndicatorArrowLeft: {
610 // From windowsstyle but modified to enable AA
611 if (option->rect.width() <= 1 || option->rect.height() <= 1)
612 break;
613
614 QRect r = option->rect;
615 int size = qMin(r.height(), r.width());
616 QPixmap pixmap;
617 QString pixmapName=QString("%1-%2-%3-%4-%5-%6")
618 .arg("$qt_ia").arg(metaObject()->className())
619 .arg(uint(option->state)).arg(element)
620 .arg(size).arg(option->palette.cacheKey());
621 if (!QPixmapCache::find(pixmapName, &pixmap)) {
622 int border = size / 5;
623 int sqsize = 2 * (size / 2);
624 QImage image(sqsize, sqsize, QImage::Format_ARGB32);
625 image.fill(Qt::transparent);
626 QPainter imagePainter(&image);
627 imagePainter.setRenderHint(QPainter::Antialiasing, true);
628 imagePainter.translate(0.5, 0.5);
629 QPolygon a;
630 switch (element) {
631 case PE_IndicatorArrowUp:
632 a.setPoints(3, border, sqsize / 2, sqsize / 2, border, sqsize - border, sqsize / 2);
633 break;
634 case PE_IndicatorArrowDown:
635 a.setPoints(3, border, sqsize / 2, sqsize / 2, sqsize - border, sqsize - border, sqsize / 2);
636 break;
637 case PE_IndicatorArrowRight:
638 a.setPoints(3, sqsize - border, sqsize / 2, sqsize / 2, border, sqsize / 2, sqsize - border);
639 break;
640 case PE_IndicatorArrowLeft:
641 a.setPoints(3, border, sqsize / 2, sqsize / 2, border, sqsize / 2, sqsize - border);
642 break;
643 default:
644 break;
645 }
646
647 int bsx = 0;
648 int bsy = 0;
649
650 if (option->state & State_Sunken) {
651 bsx = pixelMetric(PM_ButtonShiftHorizontal);
652 bsy = pixelMetric(PM_ButtonShiftVertical);
653 }
654
655 QRect bounds = a.boundingRect();
656 int sx = sqsize / 2 - bounds.center().x() - 1;
657 int sy = sqsize / 2 - bounds.center().y() - 1;
658 imagePainter.translate(sx + bsx, sy + bsy);
659
660 if (!(option->state & State_Enabled)) {
661 imagePainter.setBrush(option->palette.mid().color());
662 imagePainter.setPen(option->palette.mid().color());
663 } else {
664 QColor shadow(0, 0, 0, 100);
665 imagePainter.translate(0, 1);
666 imagePainter.setPen(shadow);
667 imagePainter.setBrush(shadow);
668 QColor foreGround(255, 255, 255, 210);
669 imagePainter.drawPolygon(a);
670 imagePainter.translate(0, -1);
671 imagePainter.setPen(foreGround);
672 imagePainter.setBrush(foreGround);
673 }
674 imagePainter.drawPolygon(a);
675 imagePainter.end();
676 pixmap = QPixmap::fromImage(image);
677 QPixmapCache::insert(pixmapName, pixmap);
678 }
679 int xOffset = r.x() + (r.width() - size) / 2;
680 int yOffset = r.y() + (r.height() - size) / 2;
681 painter->drawPixmap(xOffset, yOffset, pixmap);
682 }
683 break;
684
685 default:
686 d->style->drawPrimitive(element, option, painter, widget);
687 break;
688 }
689 }
690
drawControl(ControlElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const691 void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *option,
692 QPainter *painter, const QWidget *widget) const
693 {
694 if (!panelWidget(widget))
695 return d->style->drawControl(element, option, painter, widget);
696
697 switch (element) {
698 case CE_MenuBarItem:
699 painter->save();
700 if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
701 QColor highlightOutline = StyleHelper::borderColor().lighter(120);
702 bool act = mbi->state & State_Selected && mbi->state & State_Sunken;
703 bool dis = !(mbi->state & State_Enabled);
704 StyleHelper::menuGradient(painter, option->rect, option->rect);
705 QStyleOptionMenuItem item = *mbi;
706 item.rect = mbi->rect;
707 QPalette pal = mbi->palette;
708 pal.setBrush(QPalette::ButtonText, dis ? Qt::gray : Qt::black);
709 item.palette = pal;
710 QCommonStyle::drawControl(element, &item, painter, widget);
711 QRect r = option->rect;
712
713 if (act) {
714 // Fill|
715 QColor baseColor = StyleHelper::baseColor();
716 QLinearGradient grad(option->rect.topLeft(), option->rect.bottomLeft());
717 grad.setColorAt(0, baseColor.lighter(120));
718 grad.setColorAt(1, baseColor.lighter(130));
719 painter->fillRect(option->rect.adjusted(1, 1, -1, 0), grad);
720
721 // Outline
722 painter->setPen(QPen(highlightOutline, 0));
723 painter->drawLine(QPoint(r.left(), r.top() + 1), QPoint(r.left(), r.bottom()));
724 painter->drawLine(QPoint(r.right(), r.top() + 1), QPoint(r.right(), r.bottom()));
725 painter->drawLine(QPoint(r.left() + 1, r.top()), QPoint(r.right() - 1, r.top()));
726 highlightOutline.setAlpha(60);
727 painter->setPen(QPen(highlightOutline, 0));
728 painter->drawPoint(r.topLeft());
729 painter->drawPoint(r.topRight());
730
731 QPalette pal = mbi->palette;
732 uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
733 if (!styleHint(SH_UnderlineShortcut, mbi, widget))
734 alignment |= Qt::TextHideMnemonic;
735 pal.setBrush(QPalette::Text, dis ? Qt::gray : QColor(0, 0, 0, 60));
736 drawItemText(painter, item.rect.translated(0, 1), alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text);
737 pal.setBrush(QPalette::Text, dis ? Qt::gray : Qt::white);
738 drawItemText(painter, item.rect, alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text);
739 }
740 }
741 painter->restore();
742 break;
743
744 case CE_ComboBoxLabel:
745 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
746 if (panelWidget(widget)) {
747 QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget);
748 QPalette customPal = cb->palette;
749
750 if (!cb->currentIcon.isNull()) {
751 QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal
752 : QIcon::Disabled;
753 QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode);
754 QRect iconRect(editRect);
755 iconRect.setWidth(cb->iconSize.width() + 4);
756 iconRect = alignedRect(cb->direction,
757 Qt::AlignLeft | Qt::AlignVCenter,
758 iconRect.size(), editRect);
759 if (cb->editable)
760 painter->fillRect(iconRect, customPal.brush(QPalette::Base));
761 drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap);
762
763 if (cb->direction == Qt::RightToLeft)
764 editRect.translate(-4 - cb->iconSize.width(), 0);
765 else
766 editRect.translate(cb->iconSize.width() + 4, 0);
767
768 // Reserve some space for the down-arrow
769 editRect.adjust(0, 0, -13, 0);
770 }
771
772 customPal.setBrush(QPalette::All, QPalette::ButtonText, QColor(0, 0, 0, 70));
773
774 QString text = option->fontMetrics.elidedText(cb->currentText, Qt::ElideRight, editRect.width());
775 drawItemText(painter, editRect.translated(0, 1),
776 visualAlignment(option->direction, Qt::AlignLeft | Qt::AlignVCenter),
777 customPal, cb->state & State_Enabled, text, QPalette::ButtonText);
778 customPal.setBrush(QPalette::All, QPalette::ButtonText, StyleHelper::panelTextColor());
779 drawItemText(painter, editRect,
780 visualAlignment(option->direction, Qt::AlignLeft | Qt::AlignVCenter),
781 customPal, cb->state & State_Enabled, text, QPalette::ButtonText);
782 } else {
783 d->style->drawControl(element, option, painter, widget);
784 }
785 }
786 break;
787
788 case CE_SizeGrip: {
789 painter->save();
790 QColor dark = Qt::white;
791 dark.setAlphaF(0.1);
792 int x, y, w, h;
793 option->rect.getRect(&x, &y, &w, &h);
794 int sw = qMin(h, w);
795 if (h > w)
796 painter->translate(0, h - w);
797 else
798 painter->translate(w - h, 0);
799 int sx = x;
800 int sy = y;
801 int s = 4;
802 painter->setPen(dark);
803 if (option->direction == Qt::RightToLeft) {
804 sx = x + sw;
805 for (int i = 0; i < 4; ++i) {
806 painter->drawLine(x, sy, sx, sw);
807 sx -= s;
808 sy += s;
809 }
810 } else {
811 for (int i = 0; i < 4; ++i) {
812 painter->drawLine(sx, sw, sw, sy);
813 sx += s;
814 sy += s;
815 }
816 }
817 painter->restore();
818 }
819 break;
820
821 case CE_MenuBarEmptyArea: {
822 StyleHelper::menuGradient(painter, option->rect, option->rect);
823 painter->save();
824 painter->setPen(StyleHelper::borderColor());
825 painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight());
826 painter->restore();
827 }
828 break;
829
830 case CE_ToolBar: {
831 QString key=QString("mh_toolbar %1 %2 %3").arg(option->rect.width()).arg(option->rect.height()).arg(StyleHelper::baseColor().rgb());
832
833 QPixmap pixmap;
834 QPainter *p = painter;
835 QRect rect = option->rect;
836 if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, &pixmap)) {
837 pixmap = QPixmap(option->rect.size());
838 p = new QPainter(&pixmap);
839 rect = QRect(0, 0, option->rect.width(), option->rect.height());
840 }
841
842 bool horizontal = option->state & State_Horizontal;
843 // Map offset for global window gradient
844 QPoint offset = widget->window()->mapToGlobal(option->rect.topLeft()) -
845 widget->mapToGlobal(option->rect.topLeft());
846 QRect gradientSpan;
847 if (widget) {
848 gradientSpan = QRect(offset, widget->window()->size());
849 }
850 if (horizontal)
851 StyleHelper::horizontalGradient(p, gradientSpan, rect);
852 else
853 StyleHelper::verticalGradient(p, gradientSpan, rect);
854
855 painter->setPen(StyleHelper::borderColor());
856
857 if (horizontal) {
858 // Note: This is a hack to determine if the
859 // toolbar should draw the top or bottom outline
860 // (needed for the find toolbar for instance)
861 QColor lighter(255, 255, 255, 40);
862 if (widget && widget->property("topBorder").toBool()) {
863 p->drawLine(rect.topLeft(), rect.topRight());
864 p->setPen(lighter);
865 p->drawLine(rect.topLeft() + QPoint(0, 1), rect.topRight() + QPoint(0, 1));
866 } else {
867 p->drawLine(rect.bottomLeft(), rect.bottomRight());
868 p->setPen(lighter);
869 p->drawLine(rect.topLeft(), rect.topRight());
870 }
871 } else {
872 p->drawLine(rect.topLeft(), rect.bottomLeft());
873 p->drawLine(rect.topRight(), rect.bottomRight());
874 }
875
876 if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, &pixmap)) {
877 painter->drawPixmap(rect.topLeft(), pixmap);
878 p->end();
879 delete p;
880 QPixmapCache::insert(key, pixmap);
881 }
882 }
883 break;
884
885 default:
886 d->style->drawControl(element, option, painter, widget);
887 break;
888 }
889 }
890
drawComplexControl(ComplexControl control,const QStyleOptionComplex * option,QPainter * painter,const QWidget * widget) const891 void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
892 QPainter *painter, const QWidget *widget) const
893 {
894 if (!panelWidget(widget))
895 return d->style->drawComplexControl(control, option, painter, widget);
896
897 QRect rect = option->rect;
898 switch (control) {
899 case CC_ToolButton:
900 if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
901 QRect button, menuarea;
902 button = subControlRect(control, toolbutton, SC_ToolButton, widget);
903 menuarea = subControlRect(control, toolbutton, SC_ToolButtonMenu, widget);
904
905 State bflags = toolbutton->state;
906 if (bflags & State_AutoRaise) {
907 if (!(bflags & State_MouseOver)) {
908 bflags &= ~State_Raised;
909 }
910 }
911
912 State mflags = bflags;
913 if (toolbutton->state & State_Sunken) {
914 if (toolbutton->activeSubControls & SC_ToolButton)
915 bflags |= State_Sunken;
916 if (toolbutton->activeSubControls & SC_ToolButtonMenu)
917 mflags |= State_Sunken;
918 }
919
920 QStyleOption tool(0);
921 tool.palette = toolbutton->palette;
922 if (toolbutton->subControls & SC_ToolButton) {
923 tool.rect = button;
924 tool.state = bflags;
925 drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
926 }
927
928 if (toolbutton->state & State_HasFocus) {
929 QStyleOptionFocusRect fr;
930 fr.QStyleOption::operator=(*toolbutton);
931 fr.rect.adjust(3, 3, -3, -3);
932 if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
933 fr.rect.adjust(0, 0, -pixelMetric(QStyle::PM_MenuButtonIndicator,
934 toolbutton, widget), 0);
935 QPen oldPen = painter->pen();
936 QColor focusColor = StyleHelper::panelTextColor();
937 focusColor.setAlpha(120);
938 QPen outline(focusColor, 1);
939 outline.setStyle(Qt::DotLine);
940 painter->setPen(outline);
941 QRect r = option->rect.adjusted(2, 2, -2, -2);
942 painter->drawRect(r);
943 painter->setPen(oldPen);
944 }
945
946 QStyleOptionToolButton label = *toolbutton;
947 label.palette = panelPalette(option->palette);
948 int fw = pixelMetric(PM_DefaultFrameWidth, option, widget);
949 label.rect = button.adjusted(fw, fw, -fw, -fw);
950 if (!label.icon.isNull() && isRetinaMac()) {
951 label.rect = button.adjusted(4 * fw, 4 * fw, -4 * fw, -4 * fw);
952 QPixmap px = label.icon.pixmap(64);
953 painter->drawPixmap(label.rect, px.scaled(label.rect.width() * 2, label.rect.height() * 2, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
954 } else {
955 drawControl(CE_ToolButtonLabel, &label, painter, widget);
956 }
957
958 if (toolbutton->subControls & SC_ToolButtonMenu) {
959 tool.state = mflags;
960 tool.rect = menuarea.adjusted(1, 1, -1, -1);
961 if (mflags & (State_Sunken | State_On | State_Raised)) {
962 painter->setPen(Qt::gray);
963 painter->drawLine(tool.rect.topLeft(), tool.rect.bottomLeft());
964 if (mflags & (State_Sunken)) {
965 QColor shade(0, 0, 0, 50);
966 painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade);
967 }
968 #ifndef Q_OS_MAC
969 else if (mflags & (State_MouseOver)) {
970 QColor shade(255, 255, 255, 50);
971 painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade);
972 }
973 #endif
974 }
975 tool.rect = tool.rect.adjusted(2, 2, -2, -2);
976 drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget);
977 } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
978 int arrowSize = 6;
979 QRect ir = toolbutton->rect.adjusted(1, 1, -1, -1);
980 QStyleOptionToolButton newBtn = *toolbutton;
981 newBtn.palette = panelPalette(option->palette);
982 newBtn.rect = QRect(ir.right() - arrowSize - 1,
983 ir.height() - arrowSize - 2, arrowSize, arrowSize);
984 drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
985 }
986 }
987 break;
988
989 case CC_ComboBox:
990 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
991 painter->save();
992 bool isEmpty = cb->currentText.isEmpty() && cb->currentIcon.isNull();
993 bool reverse = option->direction == Qt::RightToLeft;
994
995 // Draw tool button
996 QLinearGradient grad(option->rect.topRight(), option->rect.bottomRight());
997 grad.setColorAt(0, QColor(255, 255, 255, 20));
998 grad.setColorAt(0.4, QColor(255, 255, 255, 60));
999 grad.setColorAt(0.7, QColor(255, 255, 255, 50));
1000 grad.setColorAt(1, QColor(255, 255, 255, 40));
1001 painter->setPen(QPen(grad, 0));
1002 painter->drawLine(rect.topRight(), rect.bottomRight());
1003 painter->drawLine(rect.topLeft(), rect.bottomLeft());
1004 grad.setColorAt(0, QColor(0, 0, 0, 30));
1005 grad.setColorAt(0.4, QColor(0, 0, 0, 70));
1006 grad.setColorAt(0.7, QColor(0, 0, 0, 70));
1007 grad.setColorAt(1, QColor(0, 0, 0, 40));
1008 painter->setPen(QPen(grad, 0));
1009 if (!reverse)
1010 painter->drawLine(rect.topRight() - QPoint(1, 0), rect.bottomRight() - QPoint(1, 0));
1011 else
1012 painter->drawLine(rect.topLeft(), rect.bottomLeft());
1013 QStyleOption toolbutton = *option;
1014 if (isEmpty)
1015 toolbutton.state &= ~(State_Enabled | State_Sunken);
1016 painter->save();
1017 painter->setClipRect(toolbutton.rect.adjusted(0, 0, -2, 0));
1018 drawPrimitive(PE_PanelButtonTool, &toolbutton, painter, widget);
1019 painter->restore();
1020 // Draw arrow
1021 int menuButtonWidth = 12;
1022 int left = !reverse ? rect.right() - menuButtonWidth : rect.left();
1023 int right = !reverse ? rect.right() : rect.left() + menuButtonWidth;
1024 QRect arrowRect((left + right) / 2 + (reverse ? 6 : -6), rect.center().y() - 3, 9, 9);
1025 if (option->state & State_On)
1026 arrowRect.translate(d->style->pixelMetric(PM_ButtonShiftHorizontal, option, widget),
1027 d->style->pixelMetric(PM_ButtonShiftVertical, option, widget));
1028
1029 QStyleOption arrowOpt = *option;
1030 arrowOpt.rect = arrowRect;
1031 if (isEmpty)
1032 arrowOpt.state &= ~(State_Enabled | State_Sunken);
1033
1034 if (styleHint(SH_ComboBox_Popup, option, widget)) {
1035 arrowOpt.rect.translate(0, -3);
1036 drawPrimitive(PE_IndicatorArrowUp, &arrowOpt, painter, widget);
1037 arrowOpt.rect.translate(0, 6);
1038 drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget);
1039 } else {
1040 drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget);
1041 }
1042 painter->restore();
1043 }
1044 break;
1045 default:
1046 d->style->drawComplexControl(control, option, painter, widget);
1047 break;
1048 }
1049 }
1050
1051 // Mac style reimplements this to control the
1052 // focus widget among other things
event(QEvent * e)1053 bool ManhattanStyle::event(QEvent *e)
1054 {
1055 Q_ASSERT(d->style);
1056 return d->style->event(e);
1057 }
1058