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