manhattanstyle.cpp 38.2 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23
**
hjk's avatar
hjk committed
24 25
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
con's avatar
con committed
29 30

#include "manhattanstyle.h"
hjk's avatar
hjk committed
31

con's avatar
con committed
32
#include "styleanimator.h"
hjk's avatar
hjk committed
33

34 35
#include <coreplugin/coreconstants.h>

36
#include <utils/hostosinfo.h>
37 38
#include <utils/stylehelper.h>

39 40
#include <utils/fancymainwindow.h>

41 42 43 44 45
#include <QApplication>
#include <QComboBox>
#include <QDockWidget>
#include <QLabel>
#include <QLineEdit>
46
#include <QMenuBar>
47 48 49 50 51 52 53
#include <QPainter>
#include <QPixmap>
#include <QStatusBar>
#include <QStyleFactory>
#include <QStyleOption>
#include <QToolBar>
#include <QToolButton>
hjk's avatar
hjk committed
54

con's avatar
con committed
55
// We define a currently unused state for indicating animations
56
const QStyle::State State_Animating = QStyle::State(0x00000040);
con's avatar
con committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

// Because designer needs to disable this for widget previews
// we have a custom property that is inherited
bool styleEnabled(const QWidget *widget)
{
    const QWidget *p = widget;
    while (p) {
        if (p->property("_q_custom_style_disabled").toBool())
            return false;
            p = p->parentWidget();
    }
    return true;
}

// Consider making this a QStyle state
bool panelWidget(const QWidget *widget)
{
74 75 76
    if (!widget)
        return false;

Tobias Hunger's avatar
Tobias Hunger committed
77
    // Do not style dialogs or explicitly ignored widgets
78
    if ((widget->window()->windowFlags() & Qt::WindowType_Mask) == Qt::Dialog)
79
        return false;
con's avatar
con committed
80

81 82 83
    if (qobject_cast<const Utils::FancyMainWindow *>(widget))
        return true;

Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
84 85 86
    if (qobject_cast<const QTabBar *>(widget))
        return styleEnabled(widget);

87
    const QWidget *p = widget;
con's avatar
con committed
88
    while (p) {
89 90
        if (qobject_cast<const QToolBar *>(p) ||
            qobject_cast<const QStatusBar *>(p) ||
91
            qobject_cast<const QMenuBar *>(p) ||
92
            p->property("panelwidget").toBool())
93
            return styleEnabled(widget);
con's avatar
con committed
94 95 96 97 98
        p = p->parentWidget();
    }
    return false;
}

99 100 101 102 103 104 105
// Consider making this a QStyle state
bool lightColored(const QWidget *widget)
{
    if (!widget)
        return false;

    // Don't style dialogs or explicitly ignored widgets
106
    if ((widget->window()->windowFlags() & Qt::WindowType_Mask) == Qt::Dialog)
107 108 109 110 111 112 113 114 115 116 117
        return false;

    const QWidget *p = widget;
    while (p) {
        if (p->property("lightColored").toBool())
            return true;
        p = p->parentWidget();
    }
    return false;
}

con's avatar
con committed
118 119 120
class ManhattanStylePrivate
{
public:
121
    explicit ManhattanStylePrivate();
con's avatar
con committed
122
    void init();
hjk's avatar
hjk committed
123 124

public:
125 126 127 128
    const QImage lineeditImage;
    const QImage lineeditImage_disabled;
    const QPixmap extButtonPixmap;
    const QPixmap closeButtonPixmap;
con's avatar
con committed
129 130 131
    StyleAnimator animator;
};

132
ManhattanStylePrivate::ManhattanStylePrivate() :
133 134 135
    lineeditImage(QLatin1String(":/core/images/inputfield.png")),
    lineeditImage_disabled(QLatin1String(":/core/images/inputfield_disabled.png")),
    extButtonPixmap(QLatin1String(":/core/images/extension.png")),
136
    closeButtonPixmap(QLatin1String(Core::Constants::ICON_CLOSE))
137 138 139
{
}

con's avatar
con committed
140
ManhattanStyle::ManhattanStyle(const QString &baseStyleName)
141 142
    : QProxyStyle(QStyleFactory::create(baseStyleName)),
    d(new ManhattanStylePrivate())
con's avatar
con committed
143 144 145 146 147 148 149 150 151 152 153
{
}

ManhattanStyle::~ManhattanStyle()
{
    delete d;
    d = 0;
}

QPixmap ManhattanStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const
{
154
    return QProxyStyle::generatedIconPixmap(iconMode, pixmap, opt);
con's avatar
con committed
155 156 157 158 159
}

QSize ManhattanStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
                                       const QSize &size, const QWidget *widget) const
{
160
    QSize newSize = QProxyStyle::sizeFromContents(type, option, size, widget);
161

con's avatar
con committed
162 163
    if (type == CT_Splitter && widget && widget->property("minisplitter").toBool())
        return QSize(1, 1);
164
    else if (type == CT_ComboBox && panelWidget(widget))
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
165
        newSize += QSize(14, 0);
166
    return newSize;
con's avatar
con committed
167 168 169 170
}

QRect ManhattanStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
{
171
    return QProxyStyle::subElementRect(element, option, widget);
con's avatar
con committed
172 173 174 175 176
}

QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
                                     SubControl subControl, const QWidget *widget) const
{
177
    return QProxyStyle::subControlRect(control, option, subControl, widget);
con's avatar
con committed
178 179 180 181 182
}

QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
                                                         const QPoint &pos, const QWidget *widget) const
{
183
    return QProxyStyle::hitTestComplexControl(control, option, pos, widget);
con's avatar
con committed
184 185 186 187 188
}

int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
    int retval = 0;
189
    retval = QProxyStyle::pixelMetric(metric, option, widget);
con's avatar
con committed
190 191 192 193 194 195 196 197 198
    switch (metric) {
    case PM_SplitterWidth:
        if (widget && widget->property("minisplitter").toBool())
            retval = 1;
        break;
    case PM_ToolBarIconSize:
        if (panelWidget(widget))
            retval = 16;
        break;
199
    case PM_DockWidgetHandleExtent:
200 201
    case PM_DockWidgetSeparatorExtent:
        return 1;
202 203 204
    case PM_MenuPanelWidth:
    case PM_MenuBarHMargin:
    case PM_MenuBarVMargin:
con's avatar
con committed
205 206 207 208 209 210
    case PM_ToolBarFrameWidth:
        if (panelWidget(widget))
            retval = 1;
        break;
    case PM_ButtonShiftVertical:
    case PM_ButtonShiftHorizontal:
211
    case PM_MenuBarPanelWidth:
con's avatar
con committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
    case PM_ToolBarItemMargin:
    case PM_ToolBarItemSpacing:
        if (panelWidget(widget))
            retval = 0;
        break;
    case PM_DefaultFrameWidth:
        if (qobject_cast<const QLineEdit*>(widget) && panelWidget(widget))
            return 1;
        break;
    default:
        break;
    }
    return retval;
}

QPalette ManhattanStyle::standardPalette() const
{
229
    return QProxyStyle::standardPalette();
con's avatar
con committed
230 231 232 233
}

void ManhattanStyle::polish(QApplication *app)
{
234
    return QProxyStyle::polish(app);
con's avatar
con committed
235 236 237 238
}

void ManhattanStyle::unpolish(QApplication *app)
{
239
    return QProxyStyle::unpolish(app);
con's avatar
con committed
240 241
}

242
QPalette panelPalette(const QPalette &oldPalette, bool lightColored = false)
con's avatar
con committed
243
{
244
    QColor color = Utils::StyleHelper::panelTextColor(lightColored);
con's avatar
con committed
245 246 247 248 249 250 251 252 253 254 255 256 257
    QPalette pal = oldPalette;
    pal.setBrush(QPalette::All, QPalette::WindowText, color);
    pal.setBrush(QPalette::All, QPalette::ButtonText, color);
    pal.setBrush(QPalette::All, QPalette::Foreground, color);
    color.setAlpha(100);
    pal.setBrush(QPalette::Disabled, QPalette::WindowText, color);
    pal.setBrush(QPalette::Disabled, QPalette::ButtonText, color);
    pal.setBrush(QPalette::Disabled, QPalette::Foreground, color);
    return pal;
}

void ManhattanStyle::polish(QWidget *widget)
{
258
    QProxyStyle::polish(widget);
con's avatar
con committed
259

260
    // OxygenStyle forces a rounded widget mask on toolbars and dock widgets
Daniel Teske's avatar
Daniel Teske committed
261
    if (baseStyle()->inherits("OxygenStyle") || baseStyle()->inherits("Oxygen::Style")) {
262
        if (qobject_cast<QToolBar*>(widget) || qobject_cast<QDockWidget*>(widget)) {
263
            widget->removeEventFilter(baseStyle());
264 265
            widget->setContentsMargins(0, 0, 0, 0);
        }
con's avatar
con committed
266 267
    }
    if (panelWidget(widget)) {
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
268 269 270 271 272

        // Oxygen and possibly other styles override this
        if (qobject_cast<QDockWidget*>(widget))
            widget->setContentsMargins(0, 0, 0, 0);

con's avatar
con committed
273
        widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, true);
con's avatar
con committed
274 275
        if (qobject_cast<QToolButton*>(widget)) {
            widget->setAttribute(Qt::WA_Hover);
276
            widget->setMaximumHeight(Utils::StyleHelper::navigationWidgetHeight() - 2);
con's avatar
con committed
277 278 279
        }
        else if (qobject_cast<QLineEdit*>(widget)) {
            widget->setAttribute(Qt::WA_Hover);
280
            widget->setMaximumHeight(Utils::StyleHelper::navigationWidgetHeight() - 2);
con's avatar
con committed
281 282 283
        }
        else if (qobject_cast<QLabel*>(widget))
            widget->setPalette(panelPalette(widget->palette()));
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
284
        else if (widget->property("panelwidget_singlerow").toBool())
285
            widget->setFixedHeight(Utils::StyleHelper::navigationWidgetHeight());
con's avatar
con committed
286
        else if (qobject_cast<QStatusBar*>(widget))
287
            widget->setFixedHeight(Utils::StyleHelper::navigationWidgetHeight() + 2);
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
288
        else if (qobject_cast<QComboBox*>(widget)) {
289
            widget->setMaximumHeight(Utils::StyleHelper::navigationWidgetHeight() - 2);
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
290 291
            widget->setAttribute(Qt::WA_Hover);
        }
con's avatar
con committed
292 293 294 295 296
    }
}

void ManhattanStyle::unpolish(QWidget *widget)
{
297
    QProxyStyle::unpolish(widget);
con's avatar
con committed
298
    if (panelWidget(widget)) {
con's avatar
con committed
299
        widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, false);
con's avatar
con committed
300 301 302 303
        if (qobject_cast<QTabBar*>(widget))
            widget->setAttribute(Qt::WA_Hover, false);
        else if (qobject_cast<QToolBar*>(widget))
            widget->setAttribute(Qt::WA_Hover, false);
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
304 305
        else if (qobject_cast<QComboBox*>(widget))
            widget->setAttribute(Qt::WA_Hover, false);
con's avatar
con committed
306 307 308 309 310
    }
}

void ManhattanStyle::polish(QPalette &pal)
{
311
    QProxyStyle::polish(pal);
con's avatar
con committed
312 313
}

314
QIcon ManhattanStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const
con's avatar
con committed
315 316 317 318
{
    QIcon icon;
    switch (standardIcon) {
    case QStyle::SP_TitleBarCloseButton:
319 320
    case QStyle::SP_ToolBarHorizontalExtensionButton:
        return QIcon(standardPixmap(standardIcon, option, widget));
con's avatar
con committed
321
    default:
322
        icon = baseStyle()->standardIcon(standardIcon, option, widget);
con's avatar
con committed
323 324 325 326 327 328 329
    }
    return icon;
}

QPixmap ManhattanStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
                                       const QWidget *widget) const
{
330
    if (widget && !panelWidget(widget))
331
        return QProxyStyle::standardPixmap(standardPixmap, opt, widget);
332

con's avatar
con committed
333 334
    QPixmap pixmap;
    switch (standardPixmap) {
335 336
    case QStyle::SP_ToolBarHorizontalExtensionButton:
        pixmap = d->extButtonPixmap;
337
        break;
338 339
    case QStyle::SP_TitleBarCloseButton:
        pixmap = d->closeButtonPixmap;
con's avatar
con committed
340 341
        break;
    default:
342
        pixmap = QProxyStyle::standardPixmap(standardPixmap, opt, widget);
343
        break;
con's avatar
con committed
344 345 346 347 348 349 350
    }
    return pixmap;
}

int ManhattanStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
                              QStyleHintReturn *returnData) const
{
351
    int ret = QProxyStyle::styleHint(hint, option, widget, returnData);
con's avatar
con committed
352
    switch (hint) {
353 354 355 356 357
    // Make project explorer alternate rows all the way
    case QStyle::SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
        if (widget && widget->property("AlternateEmpty").toBool())
            ret = true;
        break;
con's avatar
con committed
358
    case QStyle::SH_EtchDisabledText:
359 360
        if (panelWidget(widget))
            ret = false;
con's avatar
con committed
361
        break;
362 363 364
    case QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren:
        ret = true;
        break;
con's avatar
con committed
365
    default:
366
        break;
con's avatar
con committed
367 368 369 370 371 372 373 374
    }
    return ret;
}

void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
                                   QPainter *painter, const QWidget *widget) const
{
    if (!panelWidget(widget))
375
        return QProxyStyle::drawPrimitive(element, option, painter, widget);
con's avatar
con committed
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404

    bool animating = (option->state & State_Animating);
    int state = option->state;
    QRect rect = option->rect;
    QRect oldRect;
    QRect newRect;
    if (widget && (element == PE_PanelButtonTool) && !animating) {
        QWidget *w = const_cast<QWidget *> (widget);
        int oldState = w->property("_q_stylestate").toInt();
        oldRect = w->property("_q_stylerect").toRect();
        newRect = w->rect();
        w->setProperty("_q_stylestate", (int)option->state);
        w->setProperty("_q_stylerect", w->rect());

        // Determine the animated transition
        bool doTransition = ((state & State_On)         != (oldState & State_On)     ||
                             (state & State_MouseOver)  != (oldState & State_MouseOver));
        if (oldRect != newRect)
        {
            doTransition = false;
            d->animator.stopAnimation(widget);
        }

        if (doTransition) {
            QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
            QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
            Animation *anim = d->animator.widgetAnimation(widget);
            QStyleOption opt = *option;
            opt.state = (QStyle::State)oldState;
405
            opt.state |= State_Animating;
con's avatar
con committed
406 407 408 409 410 411 412 413 414 415 416
            startImage.fill(0);
            Transition *t = new Transition;
            t->setWidget(w);
            QPainter startPainter(&startImage);
            if (!anim) {
                drawPrimitive(element, &opt, &startPainter, widget);
            } else {
                anim->paint(&startPainter, &opt);
                d->animator.stopAnimation(widget);
            }
            QStyleOption endOpt = *option;
417
            endOpt.state |= State_Animating;
con's avatar
con committed
418 419 420 421 422 423
            t->setStartImage(startImage);
            d->animator.startAnimation(t);
            endImage.fill(0);
            QPainter endPainter(&endImage);
            drawPrimitive(element, &endOpt, &endPainter, widget);
            t->setEndImage(endImage);
424 425 426 427
            if (oldState & State_MouseOver)
                t->setDuration(150);
            else
                t->setDuration(75);
con's avatar
con committed
428 429 430 431 432
            t->setStartTime(QTime::currentTime());
        }
    }

    switch (element) {
433 434 435 436 437 438
    case PE_IndicatorDockWidgetResizeHandle:
        painter->fillRect(option->rect, Utils::StyleHelper::borderColor());
        break;
    case PE_FrameDockWidget:
        QCommonStyle::drawPrimitive(element, option, painter, widget);
        break;
con's avatar
con committed
439 440 441
    case PE_PanelLineEdit:
        {
            painter->save();
442 443 444 445 446 447

            // Fill the line edit background
            QRect filledRect = option->rect.adjusted(1, 1, -1, -1);
            painter->setBrushOrigin(filledRect.topLeft());
            painter->fillRect(filledRect, option->palette.base());

con's avatar
con committed
448
            if (option->state & State_Enabled)
449
                Utils::StyleHelper::drawCornerImage(d->lineeditImage, painter, option->rect, 5, 5, 5, 5);
con's avatar
con committed
450
            else
451
                Utils::StyleHelper::drawCornerImage(d->lineeditImage_disabled, painter, option->rect, 5, 5, 5, 5);
con's avatar
con committed
452 453

            if (option->state & State_HasFocus || option->state & State_MouseOver) {
454
                QColor hover = Utils::StyleHelper::baseColor();
con's avatar
con committed
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
                if (state & State_HasFocus)
                    hover.setAlpha(100);
                else
                    hover.setAlpha(50);

                painter->setPen(QPen(hover, 1));
                painter->drawRect(option->rect.adjusted(1, 1, -2 ,-2));
            }
            painter->restore();
        }
        break;

    case PE_FrameStatusBarItem:
        break;

    case PE_PanelButtonTool: {
            Animation *anim = d->animator.widgetAnimation(widget);
            if (!animating && anim) {
                anim->paint(painter, option);
            } else {
                bool pressed = option->state & State_Sunken || option->state & State_On;
                QColor shadow(0, 0, 0, 30);
                painter->setPen(shadow);
                if (pressed) {
479 480 481
                    QColor shade(0, 0, 0, 40);
                    painter->fillRect(rect, shade);
                    painter->drawLine(rect.topLeft() + QPoint(1, 0), rect.topRight() - QPoint(1, 0));
con's avatar
con committed
482
                    painter->drawLine(rect.topLeft(), rect.bottomLeft());
483 484
                    painter->drawLine(rect.topRight(), rect.bottomRight());
                   // painter->drawLine(rect.bottomLeft()  + QPoint(1, 0), rect.bottomRight()  - QPoint(1, 0));
con's avatar
con committed
485 486 487
                    QColor highlight(255, 255, 255, 30);
                    painter->setPen(highlight);
                }
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
488 489
                else if (option->state & State_Enabled &&
                         option->state & State_MouseOver) {
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
490
                    QColor lighter(255, 255, 255, 37);
con's avatar
con committed
491 492
                    painter->fillRect(rect, lighter);
                }
493 494 495 496 497 498 499 500 501 502 503
                if (option->state & State_HasFocus && (option->state & State_KeyboardFocusChange)) {
                    QColor highlight = option->palette.highlight().color();
                    highlight.setAlphaF(0.4);
                    painter->setPen(QPen(highlight.lighter(), 1));
                    highlight.setAlphaF(0.3);
                    painter->setBrush(highlight);
                    painter->setRenderHint(QPainter::Antialiasing);
                    QRectF rect = option->rect;
                    rect.translate(0.5, 0.5);
                    painter->drawRoundedRect(rect.adjusted(2, 2, -3, -3), 2, 2);
                }
con's avatar
con committed
504 505 506 507 508 509 510
           }
        }
        break;

    case PE_PanelStatusBar:
        {
            painter->save();
511 512
            QLinearGradient grad = Utils::StyleHelper::statusBarGradient(rect);
            painter->fillRect(rect, grad);
con's avatar
con committed
513 514 515
            painter->setPen(QColor(255, 255, 255, 60));
            painter->drawLine(rect.topLeft() + QPoint(0,1),
                              rect.topRight()+ QPoint(0,1));
516
            painter->setPen(Utils::StyleHelper::borderColor().darker(110));
con's avatar
con committed
517 518 519 520 521 522 523
            painter->drawLine(rect.topLeft(), rect.topRight());
            painter->restore();
        }
        break;

    case PE_IndicatorToolBarSeparator:
        {
524
            QColor separatorColor = Utils::StyleHelper::borderColor();
con's avatar
con committed
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
            separatorColor.setAlpha(100);
            painter->setPen(separatorColor);
            const int margin = 6;
            if (option->state & State_Horizontal) {
                const int offset = rect.width()/2;
                painter->drawLine(rect.bottomLeft().x() + offset,
                            rect.bottomLeft().y() - margin,
                            rect.topLeft().x() + offset,
                            rect.topLeft().y() + margin);
            } else { //Draw vertical separator
                const int offset = rect.height()/2;
                painter->setPen(QPen(option->palette.background().color().darker(110)));
                painter->drawLine(rect.topLeft().x() + margin ,
                            rect.topLeft().y() + offset,
                            rect.topRight().x() - margin,
                            rect.topRight().y() + offset);
            }
        }
        break;

    case PE_IndicatorToolBarHandle:
        {
            bool horizontal = option->state & State_Horizontal;
            painter->save();
            QPainterPath path;
550 551
            int x = option->rect.x() + (horizontal ? 2 : 6);
            int y = option->rect.y() + (horizontal ? 6 : 2);
con's avatar
con committed
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
            static const int RectHeight = 2;
            if (horizontal) {
                while (y < option->rect.height() - RectHeight - 6) {
                    path.moveTo(x, y);
                    path.addRect(x, y, RectHeight, RectHeight);
                    y += 6;
                }
            } else {
                while (x < option->rect.width() - RectHeight - 6) {
                    path.moveTo(x, y);
                    path.addRect(x, y, RectHeight, RectHeight);
                    x += 6;
                }
            }

            painter->setPen(Qt::NoPen);
568
            QColor dark = Utils::StyleHelper::borderColor();
con's avatar
con committed
569 570
            dark.setAlphaF(0.4);

571
            QColor light = Utils::StyleHelper::baseColor();
con's avatar
con committed
572 573 574 575 576 577 578 579 580 581 582 583 584 585
            light.setAlphaF(0.4);

            painter->fillPath(path, light);
            painter->save();
            painter->translate(1, 1);
            painter->fillPath(path, dark);
            painter->restore();
            painter->translate(3, 3);
            painter->fillPath(path, light);
            painter->translate(1, 1);
            painter->fillPath(path, dark);
            painter->restore();
        }
        break;
586 587 588 589 590
    case PE_IndicatorArrowUp:
    case PE_IndicatorArrowDown:
    case PE_IndicatorArrowRight:
    case PE_IndicatorArrowLeft:
        {
591
            Utils::StyleHelper::drawArrow(element, painter, option);
592 593
        }
        break;
con's avatar
con committed
594 595

    default:
596
        QProxyStyle::drawPrimitive(element, option, painter, widget);
con's avatar
con committed
597 598 599 600 601 602 603 604
        break;
    }
}

void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *option,
                                 QPainter *painter, const QWidget *widget) const
{
    if (!panelWidget(widget))
605
        return QProxyStyle::drawControl(element, option, painter, widget);
con's avatar
con committed
606 607

    switch (element) {
608 609 610 611 612 613 614 615 616 617
    case CE_Splitter:
        painter->fillRect(option->rect, Utils::StyleHelper::borderColor());
        break;

    case CE_TabBarTabShape:
        // Most styles draw a single dark outline. This looks rather ugly when combined with our
        // single pixel dark separator so we adjust the first tab to compensate for this

        if (const QStyleOptionTabV3 *tab = qstyleoption_cast<const QStyleOptionTabV3 *>(option)) {
            QStyleOptionTabV3 adjustedTab = *tab;
618 619 620 621
            if (tab->cornerWidgets == QStyleOptionTab::NoCornerWidgets && (
                    tab->position == QStyleOptionTab::Beginning ||
                    tab->position == QStyleOptionTab::OnlyOneTab))
            {
622 623 624 625 626 627 628 629 630 631
                if (option->direction == Qt::LeftToRight)
                    adjustedTab.rect = adjustedTab.rect.adjusted(-1, 0, 0, 0);
                else
                    adjustedTab.rect = adjustedTab.rect.adjusted(0, 0, 1 ,0);
            }
            QProxyStyle::drawControl(element, &adjustedTab, painter, widget);
            return;
        }
        break;

632 633 634 635
    case CE_MenuBarItem:
        painter->save();
        if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
            QColor highlightOutline = Utils::StyleHelper::borderColor().lighter(120);
636
            bool act = mbi->state & State_Sunken;
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
            bool dis = !(mbi->state & State_Enabled);
            Utils::StyleHelper::menuGradient(painter, option->rect, option->rect);
            QStyleOptionMenuItem item = *mbi;
            item.rect = mbi->rect;
            QPalette pal = mbi->palette;
            pal.setBrush(QPalette::ButtonText, dis ? Qt::gray : Qt::black);
            item.palette = pal;
            QCommonStyle::drawControl(element, &item, painter, widget);
            QRect r = option->rect;

            if (act) {
                // Fill|
                QColor baseColor = Utils::StyleHelper::baseColor();
                QLinearGradient grad(option->rect.topLeft(), option->rect.bottomLeft());
                grad.setColorAt(0, baseColor.lighter(120));
                grad.setColorAt(1, baseColor.lighter(130));
                painter->fillRect(option->rect.adjusted(1, 1, -1, 0), grad);

                // Outline
                painter->setPen(QPen(highlightOutline, 0));
                painter->drawLine(QPoint(r.left(), r.top() + 1), QPoint(r.left(), r.bottom()));
                painter->drawLine(QPoint(r.right(), r.top() + 1), QPoint(r.right(), r.bottom()));
                painter->drawLine(QPoint(r.left() + 1, r.top()), QPoint(r.right() - 1, r.top()));
                highlightOutline.setAlpha(60);
                painter->setPen(QPen(highlightOutline, 0));
                painter->drawPoint(r.topLeft());
                painter->drawPoint(r.topRight());

                QPalette pal = mbi->palette;
                uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
                if (!styleHint(SH_UnderlineShortcut, mbi, widget))
                    alignment |= Qt::TextHideMnemonic;
                pal.setBrush(QPalette::Text, dis ? Qt::gray : QColor(0, 0, 0, 60));
                drawItemText(painter, item.rect.translated(0, 1), alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text);
                pal.setBrush(QPalette::Text, dis ? Qt::gray : Qt::white);
                drawItemText(painter, item.rect, alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text);
            }
        }
        painter->restore();
        break;

con's avatar
con committed
678 679 680
    case CE_ComboBoxLabel:
        if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
            if (panelWidget(widget)) {
681
                painter->save();
con's avatar
con committed
682 683
                QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget);
                QPalette customPal = cb->palette;
684
                bool drawIcon = !(widget && widget->property("hideicon").toBool());
con's avatar
con committed
685

686
                if (!cb->currentIcon.isNull() && drawIcon) {
con's avatar
con committed
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
                    QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal
                                                                 : QIcon::Disabled;
                    QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode);
                    QRect iconRect(editRect);
                    iconRect.setWidth(cb->iconSize.width() + 4);
                    iconRect = alignedRect(cb->direction,
                                           Qt::AlignLeft | Qt::AlignVCenter,
                                           iconRect.size(), editRect);
                    if (cb->editable)
                        painter->fillRect(iconRect, customPal.brush(QPalette::Base));
                    drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap);

                    if (cb->direction == Qt::RightToLeft)
                        editRect.translate(-4 - cb->iconSize.width(), 0);
                    else
                        editRect.translate(cb->iconSize.width() + 4, 0);
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
703 704 705

                    // Reserve some space for the down-arrow
                    editRect.adjust(0, 0, -13, 0);
con's avatar
con committed
706 707
                }

708 709 710 711 712 713 714 715 716 717 718 719 720 721
                QLatin1Char asterisk('*');
                int elideWidth = editRect.width();

                bool notElideAsterisk = widget && widget->property("notelideasterisk").toBool()
                                        && cb->currentText.endsWith(asterisk)
                                        && option->fontMetrics.width(cb->currentText) > elideWidth;

                QString text;
                if (notElideAsterisk) {
                    elideWidth -= option->fontMetrics.width(asterisk);
                    text = asterisk;
                }
                text.prepend(option->fontMetrics.elidedText(cb->currentText, Qt::ElideRight, elideWidth));

722 723
                if ((option->state & State_Enabled)) {
                    painter->setPen(QColor(0, 0, 0, 70));
724
                    painter->drawText(editRect.adjusted(1, 0, -1, 0), Qt::AlignLeft | Qt::AlignVCenter, text);
725
                } else {
726
                    painter->setOpacity(0.8);
727 728
                }
                painter->setPen(Utils::StyleHelper::panelTextColor());
729
                painter->drawText(editRect.adjusted(1, 0, -1, 0), Qt::AlignLeft | Qt::AlignVCenter, text);
730 731

                painter->restore();
con's avatar
con committed
732
            } else {
733
                QProxyStyle::drawControl(element, option, painter, widget);
con's avatar
con committed
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
            }
        }
        break;

    case CE_SizeGrip: {
            painter->save();
            QColor dark = Qt::white;
            dark.setAlphaF(0.1);
            int x, y, w, h;
            option->rect.getRect(&x, &y, &w, &h);
            int sw = qMin(h, w);
            if (h > w)
                painter->translate(0, h - w);
            else
                painter->translate(w - h, 0);
            int sx = x;
            int sy = y;
            int s = 4;
            painter->setPen(dark);
            if (option->direction == Qt::RightToLeft) {
                sx = x + sw;
                for (int i = 0; i < 4; ++i) {
                    painter->drawLine(x, sy, sx, sw);
                    sx -= s;
                    sy += s;
                }
            } else {
                for (int i = 0; i < 4; ++i) {
                    painter->drawLine(sx, sw, sw, sy);
                    sx += s;
                    sy += s;
                }
            }
            painter->restore();
        }
        break;

771 772 773 774 775 776 777 778 779
    case CE_MenuBarEmptyArea: {
            Utils::StyleHelper::menuGradient(painter, option->rect, option->rect);
            painter->save();
            painter->setPen(Utils::StyleHelper::borderColor());
            painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight());
            painter->restore();
        }
        break;

con's avatar
con committed
780 781 782
    case CE_ToolBar:
        {
            QRect rect = option->rect;
783
            bool horizontal = option->state & State_Horizontal;
784 785 786 787 788 789 790 791 792 793 794 795 796 797
            rect = option->rect;

            // Map offset for global window gradient
            QPoint offset = widget->window()->mapToGlobal(option->rect.topLeft()) -
                            widget->mapToGlobal(option->rect.topLeft());
            QRect gradientSpan;
            if (widget)
                gradientSpan = QRect(offset, widget->window()->size());

            bool drawLightColored = lightColored(widget);
            if (horizontal)
                Utils::StyleHelper::horizontalGradient(painter, gradientSpan, rect, drawLightColored);
            else
                Utils::StyleHelper::verticalGradient(painter, gradientSpan, rect, drawLightColored);
con's avatar
con committed
798

799 800 801 802
            if (!drawLightColored)
                painter->setPen(Utils::StyleHelper::borderColor());
            else
                painter->setPen(QColor(0x888888));
con's avatar
con committed
803 804

            if (horizontal) {
805 806 807
                // Note: This is a hack to determine if the
                // toolbar should draw the top or bottom outline
                // (needed for the find toolbar for instance)
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
808
                QColor lighter(Utils::StyleHelper::sidebarHighlight());
809 810
                if (drawLightColored)
                    lighter = QColor(255, 255, 255, 180);
811
                if (widget && widget->property("topBorder").toBool()) {
812 813 814
                    painter->drawLine(rect.topLeft(), rect.topRight());
                    painter->setPen(lighter);
                    painter->drawLine(rect.topLeft() + QPoint(0, 1), rect.topRight() + QPoint(0, 1));
con's avatar
con committed
815
                } else {
816 817 818
                    painter->drawLine(rect.bottomLeft(), rect.bottomRight());
                    painter->setPen(lighter);
                    painter->drawLine(rect.topLeft(), rect.topRight());
con's avatar
con committed
819 820
                }
            } else {
821 822
                painter->drawLine(rect.topLeft(), rect.bottomLeft());
                painter->drawLine(rect.topRight(), rect.bottomRight());
con's avatar
con committed
823 824 825
            }
        }
        break;
826

con's avatar
con committed
827
    default:
828
        QProxyStyle::drawControl(element, option, painter, widget);
con's avatar
con committed
829 830 831 832 833 834 835 836
        break;
    }
}

void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
                                        QPainter *painter, const QWidget *widget) const
{
    if (!panelWidget(widget))
837
         return     QProxyStyle::drawComplexControl(control, option, painter, widget);
con's avatar
con committed
838 839 840 841 842

    QRect rect = option->rect;
    switch (control) {
    case CC_ToolButton:
        if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
843 844 845 846 847 848
            bool reverse = option->direction == Qt::RightToLeft;
            bool drawborder = (widget && widget->property("showborder").toBool());

            if (drawborder)
                drawButtonSeparator(painter, rect, reverse);

con's avatar
con committed
849 850 851 852 853 854
            QRect button, menuarea;
            button = subControlRect(control, toolbutton, SC_ToolButton, widget);
            menuarea = subControlRect(control, toolbutton, SC_ToolButtonMenu, widget);

            State bflags = toolbutton->state;
            if (bflags & State_AutoRaise) {
855
                if (!(bflags & State_MouseOver))
con's avatar
con committed
856 857 858 859
                    bflags &= ~State_Raised;
            }

            State mflags = bflags;
860 861 862 863 864 865
            if (toolbutton->state & State_Sunken) {
                if (toolbutton->activeSubControls & SC_ToolButton)
                    bflags |= State_Sunken;
                if (toolbutton->activeSubControls & SC_ToolButtonMenu)
                    mflags |= State_Sunken;
            }
con's avatar
con committed
866 867 868 869

            QStyleOption tool(0);
            tool.palette = toolbutton->palette;
            if (toolbutton->subControls & SC_ToolButton) {
870 871 872
                tool.rect = button;
                tool.state = bflags;
                drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
con's avatar
con committed
873 874 875
            }

            QStyleOptionToolButton label = *toolbutton;
876 877

            label.palette = panelPalette(option->palette, lightColored(widget));
con's avatar
con committed
878 879
            int fw = pixelMetric(PM_DefaultFrameWidth, option, widget);
            label.rect = button.adjusted(fw, fw, -fw, -fw);
880

con's avatar
con committed
881 882 883 884 885 886 887 888 889 890 891
            drawControl(CE_ToolButtonLabel, &label, painter, widget);

            if (toolbutton->subControls & SC_ToolButtonMenu) {
                tool.state = mflags;
                tool.rect = menuarea.adjusted(1, 1, -1, -1);
                if (mflags & (State_Sunken | State_On | State_Raised)) {
                    painter->setPen(Qt::gray);
                    painter->drawLine(tool.rect.topLeft(), tool.rect.bottomLeft());
                    if (mflags & (State_Sunken)) {
                        QColor shade(0, 0, 0, 50);
                        painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade);
892
                    } else if (!Utils::HostOsInfo::isMacHost() && (mflags & State_MouseOver)) {
con's avatar
con committed
893 894 895 896 897 898
                        QColor shade(255, 255, 255, 50);
                        painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade);
                    }
                }
                tool.rect = tool.rect.adjusted(2, 2, -2, -2);
                drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget);
899 900
            } else if (toolbutton->features & QStyleOptionToolButton::HasMenu
                       && !widget->property("noArrow").toBool()) {
901
                int arrowSize = 6;
con's avatar
con committed
902 903 904
                QRect ir = toolbutton->rect.adjusted(1, 1, -1, -1);
                QStyleOptionToolButton newBtn = *toolbutton;
                newBtn.palette = panelPalette(option->palette);
905 906
                newBtn.rect = QRect(ir.right() - arrowSize - 1,
                                    ir.height() - arrowSize - 2, arrowSize, arrowSize);
907
                drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
con's avatar
con committed
908 909 910 911 912
            }
        }
        break;

    case CC_ComboBox:
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
913
        if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
con's avatar
con committed
914
            painter->save();
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
915 916
            bool isEmpty = cb->currentText.isEmpty() && cb->currentIcon.isNull();
            bool reverse = option->direction == Qt::RightToLeft;
917 918
            bool drawborder = !(widget && widget->property("hideborder").toBool());
            bool alignarrow = !(widget && widget->property("alignarrow").toBool());
con's avatar
con committed
919

920 921 922
            if (drawborder)
                drawButtonSeparator(painter, rect, reverse);

Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
923
            QStyleOption toolbutton = *option;
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
924 925
            if (isEmpty)
                toolbutton.state &= ~(State_Enabled | State_Sunken);
926
            painter->save();
927 928
            if (drawborder)
                painter->setClipRect(toolbutton.rect.adjusted(0, 0, -2, 0));
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
929
            drawPrimitive(PE_PanelButtonTool, &toolbutton, painter, widget);
930
            painter->restore();
con's avatar
con committed
931
            // Draw arrow
932
            int menuButtonWidth = 12;
con's avatar
con committed
933 934
            int left = !reverse ? rect.right() - menuButtonWidth : rect.left();
            int right = !reverse ? rect.right() : rect.left() + menuButtonWidth;
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
935
            QRect arrowRect((left + right) / 2 + (reverse ? 6 : -6), rect.center().y() - 3, 9, 9);
936 937

            if (!alignarrow) {
938 939 940 941 942
                int labelwidth = option->fontMetrics.width(cb->currentText);
                if (reverse)
                    arrowRect.moveLeft(qMax(rect.width() - labelwidth - menuButtonWidth - 2, 4));
                else
                    arrowRect.moveLeft(qMin(labelwidth + menuButtonWidth - 2, rect.width() - menuButtonWidth - 4));
943
            }
con's avatar
con committed
944
            if (option->state & State_On)
945 946
                arrowRect.translate(QProxyStyle::pixelMetric(PM_ButtonShiftHorizontal, option, widget),
                                    QProxyStyle::pixelMetric(PM_ButtonShiftVertical, option, widget));
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
947

con's avatar
con committed
948 949
            QStyleOption arrowOpt = *option;
            arrowOpt.rect = arrowRect;
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
950 951 952
            if (isEmpty)
                arrowOpt.state &= ~(State_Enabled | State_Sunken);

Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
953 954 955 956 957 958 959 960
            if (styleHint(SH_ComboBox_Popup, option, widget)) {
                arrowOpt.rect.translate(0, -3);
                drawPrimitive(PE_IndicatorArrowUp, &arrowOpt, painter, widget);
                arrowOpt.rect.translate(0, 6);
                drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget);
            } else {
                drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget);
            }
961

con's avatar
con committed
962 963 964
            painter->restore();
        }
        break;
965

con's avatar
con committed
966
    default:
967
        QProxyStyle::drawComplexControl(control, option, painter, widget);
con's avatar
con committed
968 969 970
        break;
    }
}
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990

void ManhattanStyle::drawButtonSeparator(QPainter *painter, const QRect &rect, bool reverse) const
{
    QLinearGradient grad(rect.topRight(), rect.bottomRight());
    grad.setColorAt(0, QColor(255, 255, 255, 20));
    grad.setColorAt(0.4, QColor(255, 255, 255, 60));
    grad.setColorAt(0.7, QColor(255, 255, 255, 50));
    grad.setColorAt(1, QColor(255, 255, 255, 40));
    painter->setPen(QPen(grad, 0));
    painter->drawLine(rect.topRight(), rect.bottomRight());
    grad.setColorAt(0, QColor(0, 0, 0, 30));
    grad.setColorAt(0.4, QColor(0, 0, 0, 70));
    grad.setColorAt(0.7, QColor(0, 0, 0, 70));
    grad.setColorAt(1, QColor(0, 0, 0, 40));
    painter->setPen(QPen(grad, 0));
    if (!reverse)
       painter->drawLine(rect.topRight() - QPoint(1,0), rect.bottomRight() - QPoint(1,0));
    else
       painter->drawLine(rect.topLeft(), rect.bottomLeft());
 }