pynoto / src / Main / PynotoStyle.cpp

#include <QDebug>
#include <QWidget>
#include <QVariant>
#include <QDockWidget>
#include <QToolButton>
#include <QLineEdit>
#include <QLabel>
#include <QStatusBar>
#include <QComboBox>
#include <QPainter>
#include <QTimer>
#include "Include/PynotoApplication.h"
#include "Include/IIconProvider.h"
#include "PynotoStyle.h"
#include "Settings.h"

PynotoStyle::PynotoStyle(QStyle *baseStyle):
    QProxyStyle(baseStyle)
{
    Main::Settings set;
    _panelColor = set.color();
    createPanelImage();

    _arrowDown = Aux::icons()->icon("arrowdown");
    _hover = QColor(255, 255, 255, 100);
    _pbtn  = Aux::icons()->pixmap("pushbutton");
    _pbtnHover = Aux::icons()->pixmap("pushbutton_hover");
    _pbtnPressed = Aux::icons()->pixmap("pushbutton_pressed");

    connect(Aux::app(), SIGNAL(preferencesChanged(QString,QVariant)), SLOT(onPreferencesChanged(QString,QVariant)));
}

bool PynotoStyle::isPanel(const QWidget* widget) const
{
    if (!widget)
        return false;

    const QWidget *w = widget;
    while(w){
        if (w && w->property("panelWidget").toBool()){
            //qDebug() << w << widget;
            return true;
        }
        w = w->parentWidget();
    }
    return false;
}

QPalette PynotoStyle::panelPalette(const QPalette &oldPalette, bool lightColored)
{
    QColor color("#FFFFFF");
    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 PynotoStyle::polish(QWidget *widget)
{
    QProxyStyle::polish(widget);

    if (isPanel(widget)){
        if (qobject_cast<QDockWidget*>(widget))
            widget->setContentsMargins(0, 0, 0, 0);

        widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, true);
        if (qobject_cast<QToolButton*>(widget)) {
            widget->setAttribute(Qt::WA_Hover);
            widget->setMaximumHeight(23);
        }
        else if (qobject_cast<QLineEdit*>(widget)) {
            widget->setAttribute(Qt::WA_Hover);
            widget->setMaximumHeight(23);
        }
        else if (qobject_cast<QLabel*>(widget))
            widget->setPalette(panelPalette(widget->palette()));
        else if (qobject_cast<QStatusBar*>(widget))
            widget->setFixedHeight(25);
        else if (qobject_cast<QComboBox*>(widget)) {
            widget->setMaximumHeight(23);
            widget->setAttribute(Qt::WA_Hover);
        }
        if (widget->property("panelWidget").toBool()) {
            widget->setMaximumHeight(25);
            widget->setMinimumHeight(25);
            widget->setBackgroundRole(QPalette::Background);
            widget->setAutoFillBackground(true);
            QPalette pal = widget->palette();
            for (int i = 0; i < QPalette::NColorGroups; ++i) {
                QColor color = pal.brush(QPalette::ColorGroup(i), QPalette::Window).color();
                pal.setBrush(QPalette::ColorGroup(i), QPalette::Background, QBrush(color, _panel));
            }
            widget->setPalette(pal);
        }
        QPalette pal = widget->palette();
        pal.setColor(QPalette::WindowText, isLight() ? Qt::black : Qt::white);
        pal.setColor(QPalette::ButtonText, isLight() ? Qt::black : Qt::white);
        widget->setPalette(pal);
    }
}

void PynotoStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    if (!isPanel(widget))
        return QProxyStyle::drawPrimitive(element, option, painter, widget);

    QRect rect = option->rect;
    switch (element) {
    case PE_PanelStatusBar:
        {
            painter->save();
            painter->drawPixmap(rect, _panel);
            painter->restore();
        }
        break;
    case PE_PanelButtonTool:
        {
            painter->save();
            bool hovered = option->state & State_Enabled && option->state & State_MouseOver;
            if (hovered) {
                int rshift = 0;
                if (qobject_cast<const QComboBox*>(widget))
                    rshift = -2;
                painter->fillRect(option->rect.adjusted(0, 0, rshift, 0), _hover);
                if (qobject_cast<const QToolButton*>(widget)){
                    painter->drawRect(option->rect.adjusted(0, 0, rshift, -1));
                }
            }
            if (qobject_cast<const QComboBox*>(widget)){
                drawButtonSeparator(painter, option->rect, false);
            }
            painter->restore();
        }
        break;
    default:
        QProxyStyle::drawPrimitive(element, option, painter, widget);
    }
}

void PynotoStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
    if (!isPanel(widget))
        return QProxyStyle::drawComplexControl(control, option, painter, widget);

    switch(control){
    case CC_ToolButton:
        if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
            if (widget->property("fancy").toBool()){
                drawFancyToolButton(toolbutton, painter, widget);
            } else {
                painter->save();
                bool pressed = toolbutton->state & State_Sunken || toolbutton->state & State_On;
                bool hovered = toolbutton->state & State_Enabled && toolbutton->state & State_MouseOver;
                drawPrimitive(PE_PanelButtonTool, option, painter, widget);
                QRect iconRect = pressed ? toolbutton->rect.adjusted(2, 1, 2, 2) : toolbutton->rect.adjusted(1, 0, 1, 1);
                QIcon::Mode mode = QIcon::Normal;
                if (!(toolbutton->state & State_Enabled))
                    mode = QIcon::Disabled;
                else if (hovered && pressed)
                    mode = QIcon::Active;
                toolbutton->icon.paint(painter, iconRect, Qt::AlignCenter, mode);
                if (!toolbutton->text.isEmpty()){
                    int shift = toolbutton->icon.isNull() ? 0 : toolbutton->iconSize.width()+5;
                    QPalette pal = widget->palette();
                    painter->setPen((option->state & State_Enabled) ? pal.color(QPalette::ButtonText) : pal.color(QPalette::ButtonText).lighter());
                    painter->drawText(option->rect.adjusted(shift, 0, 0, 0), toolbutton->text);
                }
                painter->restore();
            }
        }
        break;
    case CC_ComboBox:
        if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
            painter->save();
            drawPrimitive(PE_PanelButtonTool, option, painter, widget);
            int aw = 12;
            _arrowDown.paint(painter, cb->rect.adjusted(cb->rect.width()-aw, 0, -4, 0), Qt::AlignCenter);
            painter->restore();
        }
        break;
    default:
        QProxyStyle::drawComplexControl(control, option, painter, widget);
    }
}

void PynotoStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    if (!isPanel(widget))
        return QProxyStyle::drawControl(element, option, painter, widget);

    switch(element){
    case CE_Splitter:
        painter->fillRect(option->rect, QColor("#000000"));
        break;
    case CE_ComboBoxLabel:
        if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
            painter->save();
            QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget);
            QString text = option->fontMetrics.elidedText(cb->currentText, Qt::ElideRight, editRect.width());
            QPalette pal = widget->palette();
            if ((option->state & State_Enabled)) {
                painter->setPen(pal.color(QPalette::WindowText));
                painter->drawText(editRect.adjusted(1, 0, -1, 0), Qt::AlignLeft | Qt::AlignVCenter, text);
            } else {
                painter->setOpacity(0.8);
                painter->setPen(pal.color(QPalette::WindowText).lighter());
                painter->drawText(editRect.adjusted(1, 0, -1, 0), Qt::AlignLeft | Qt::AlignVCenter, text);
            }
            painter->restore();
        }
        break;
    default:
        if (!isPanel(widget))
            QProxyStyle::drawControl(element, option, painter, widget);
    }
}

int PynotoStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
    int retval = 0;
    retval = QProxyStyle::pixelMetric(metric, option, widget);
    switch (metric) {
    case PM_SplitterWidth:
        //if (widget && widget->property("minisplitter").toBool())
        retval = 1;
        break;
    case PM_DefaultFrameWidth:
        if (qobject_cast<const QLineEdit*>(widget) && isPanel(widget))
            return 1;
        break;
    default:
        break;
    }
    return retval;
}

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

    if (type == CT_Splitter && widget)// && widget->property("minisplitter").toBool()
        return QSize(1, 1);
    return newSize;
}

void PynotoStyle::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());
}

void PynotoStyle::drawFancyToolButton(const QStyleOptionToolButton* option, QPainter* painter, const QWidget* widget) const
{
    bool pressed = option->state & State_Sunken || option->state & State_On;
    bool hovered = option->state & State_Enabled && option->state & State_MouseOver;
    QPixmap btn;
    if (pressed)
        btn = _pbtnPressed;
    else if (hovered)
        btn = _pbtnHover;
    else
        btn = _pbtn;
    painter->drawPixmap(0, 0, btn, 0, 0, 10, btn.height());
    painter->drawPixmap(option->rect.adjusted(10, 0, -10, 0), btn, QRect(10, 0, btn.width()-20, btn.height()));
    painter->drawPixmap(option->rect.right()-10+1, 0, btn, btn.width()-10, 0, 10, btn.height());
    QRect iconRect = QRect(2, 2, option->rect.height()-4, option->rect.height()-4);
    QIcon::Mode mode = QIcon::Normal;
    if (!(option->state & State_Enabled))
        mode = QIcon::Disabled;
    else if (hovered && pressed)
        mode = QIcon::Active;
    option->icon.paint(painter, iconRect, Qt::AlignCenter, mode);
    QRect textRect = option->rect.adjusted(2, 0, 0, 2);
    if (!option->icon.isNull())
        textRect = textRect.adjusted(textRect.height(), 0, 0, 0);
    painter->setPen(Qt::black);
    painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, option->text);
}

void PynotoStyle::onPreferencesChanged(const QString& name, const QVariant& value)
{
    if (name == "panel-color"){
        Main::Settings set;
        QColor toColor = value.value<QColor>();
        if (toColor.alpha() == 0){
            _panelColor = set.color();
        } else {
            _panelColor = toColor;
        }
        createPanelImage();
        QTimer::singleShot(10, this, SLOT(resetStyle()));
    }
}

void PynotoStyle::createPanelImage()
{
    QPixmap p = Aux::icons()->pixmap("panel");
    _panel = QPixmap(p.width(), p.height());
    _panel.fill(_panelColor);
    QPainter ppanel(&_panel);
    ppanel.drawPixmap(0, 0, p);
    ppanel.end();
}

void PynotoStyle::resetStyle()
{
    foreach (QWidget *w, QApplication::allWidgets()){
        polish(w);
        w->update();
    }
}

bool PynotoStyle::isLight()
{
    int yiq = ((_panelColor.red()*299)+(_panelColor.green()*587)+(_panelColor.blue()*114))/1000;
    return yiq >= 128;
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.